[
  {
    "path": ".editorconfig",
    "content": "#\n# .editorconfig\n# mas\n#\n# EditorConfig 0.17.2\n#\n\nroot = true\n\n[*]\ncharset = utf-8\ncontinuation_indent_size = 0\nend_of_line = lf\nindent_size = tab\nindent_style = tab\ninsert_final_newline = true\nmax_line_length = 120\nquote_type = single\nspelling_language = en_US\ntab_width = 2\ntrim_trailing_whitespace = true\n\n[*.md]\n# Trailing spaces have meaning in Markdown\nmax_line_length = 80\ntrim_trailing_whitespace = false\n\n[{*.yaml,*.yml}]\nmax_line_length = 80\n\n[Scripts/*]\nmax_line_length = 80\n"
  },
  {
    "path": ".gitattributes",
    "content": "# Do not remove potentially intentional trailing spaces in Markdown.\n**/*.md whitespace=-blank-at-eol\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "#\n# .github/CODEOWNERS\n#\n\n/.github/ @mas-cli/admins\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/01-bug-report.yaml",
    "content": "---\nname: Bug Report\ndescription: Report a bug.\nlabels: [\\U0001F41B bug]\nbody:\n- type: textarea\n  id: config\n  attributes:\n    label: Configuration\n    description: Output of `mas config`\n    placeholder: Output of `mas config`\n    render: text\n  validations:\n    required: true\n- type: textarea\n  id: description\n  attributes:\n    label: Bug description\n    placeholder: |\n      Bug description\n\n      Include expected & actual output, plus other pertinent info\n\n      Instead of screenshots, prefer pasting copied commands & output into console blocks, formatted as instructed below\n  validations:\n    required: true\n- type: textarea\n  id: reproduction\n  attributes:\n    label: Steps to reproduce\n    placeholder: |\n      Steps to reproduce\n\n      Instead of screenshots, prefer pasting copied commands & output into console blocks, formatted as instructed below\n  validations:\n    required: true\n- type: markdown\n  attributes:\n    value: |\n      ## Console command & output formatting instructions\n\n      Provide console commands & output as copied, pasted & formatted text, instead of as screenshots.\n\n      If long descriptive text or screenshots of dialogs or apps are necessary, provide them between console blocks.\n\n      Format commands & output as follows (where `…` is a placeholder):\n\n      - Use a console block: start with ```` ```console ````, end with ```` ``` ````, each on its own line\n      - Prefix each non-console step (or comment) with two hashes & a space: `## …`\n      - Remove shell prompts; instead, prefix each console command with a dollar sign & a space: `$ …`\n      - Prefix each output line beginning with `#`, `$`, `%`, or `>` with an additional instance of that <!--\n        --> character: `##…`, `$$…`, `%%…`, or `>>…`\n      - Write all other output lines without any prefix: `…`\n\n      e.g.:\n\n      ````text\n      ```console\n      ## In the App Store GUI, click on…\n      $ mas list\n      123  App 1  (4.5.6)\n      124  App 2  (10.2)\n      $ mas outdated\n      123 App 1 (4.5.6 -> 4.5.7)\n      ```\n      ````\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/02-feature-request.yaml",
    "content": "---\nname: Feature Request\ndescription: Request a feature.\nlabels: [\\U0001F195 feature request]\nbody:\n- type: textarea\n  id: problems\n  attributes:\n    label: Problem(s) addressed\n    placeholder: |\n      Problem(s) addressed\n\n      Instead of screenshots, prefer pasting copied commands & output into console blocks, formatted as instructed below\n  validations:\n    required: true\n- type: textarea\n  id: proposals\n  attributes:\n    label: Proposed solution(s)\n    placeholder: |\n      Proposed solution(s)\n\n      Instead of screenshots, prefer pasting copied commands & output into console blocks, formatted as instructed below\n  validations:\n    required: true\n- type: markdown\n  attributes:\n    value: |\n      ## Console command & output formatting instructions\n\n      Provide console commands & output as copied, pasted & formatted text, instead of as screenshots.\n\n      If long descriptive text or screenshots of dialogs or apps are necessary, provide them between console blocks.\n\n      Format commands & output as follows (where `…` is a placeholder):\n\n      - Use a console block: start with ```` ```console ````, end with ```` ``` ````, each on its own line\n      - Prefix each non-console step (or comment) with two hashes & a space: `## …`\n      - Remove shell prompts; instead, prefix each console command with a dollar sign & a space: `$ …`\n      - Prefix each output line beginning with `#`, `$`, `%`, or `>` with an additional instance of that <!--\n        --> character: `##…`, `$$…`, `%%…`, or `>>…`\n      - Write all other output lines without any prefix: `…`\n\n      e.g.:\n\n      ````text\n      ```console\n      ## In the App Store GUI, click on…\n      $ mas list\n      123  App 1  (4.5.6)\n      124  App 2  (10.2)\n      $ mas outdated\n      123 App 1 (4.5.6 -> 4.5.7)\n      ```\n      ````\n"
  },
  {
    "path": ".github/actionlint.yaml",
    "content": "#\n# .github/actionlint.yaml\n# mas\n#\n# actionlint 1.7.11\n#\n---\nself-hosted-runner:\n  labels: [macos-26-intel]\n"
  },
  {
    "path": ".github/dependabot.yaml",
    "content": "---\nversion: 2\nupdates:\n- package-ecosystem: github-actions\n  schedule:\n    interval: daily\n  directory: /\n  labels: [📚 dependencies]\n  commit-message:\n    prefix: ⬆️\n    include: scope\n- package-ecosystem: swift\n  schedule:\n    interval: daily\n  directory: /\n  labels: [📚 dependencies]\n  commit-message:\n    prefix: ⬆️\n    include: scope\n"
  },
  {
    "path": ".github/release.yaml",
    "content": "---\nchangelog:\n  categories:\n  - title: 🚀 Features\n    labels: [🆕 feature request]\n  - title: 🐛 Bug Fixes\n    labels: [🐛 bug]\n  - title: Changes\n    labels: ['*']\n"
  },
  {
    "path": ".github/workflows/build-test.yaml",
    "content": "#\n# .github/workflows/build-test.yaml\n#\n---\nname: Build, Test, and Lint\non:\n  pull_request:\n    branches: [main]\n  push:\n    branches: [main]\nconcurrency:\n  group: ${{github.workflow}}-${{github.ref}}\n  cancel-in-progress: true\npermissions: {}\njobs:\n  build-test:\n    name: Build, Test, and Lint\n    strategy:\n      matrix:\n        include:\n        - runner: macos-14\n          xcode: brew\n        - runner: macos-15\n        - runner: macos-15-intel\n        - runner: macos-26\n        - runner: macos-26-intel\n    runs-on: ${{matrix.runner}}\n    defaults:\n      run:\n        # Force all run commands to not use Rosetta 2 on arm64\n        shell: ${{endsWith(matrix.runner, '-intel') && '/bin/zsh -Negku {0}' || 'arch -arm64 /bin/zsh -Negku {0}'}}\n    steps:\n    - name: 🛒 Checkout repo\n      env:\n        GIT_CONFIG_COUNT: 1\n        GIT_CONFIG_KEY_0: init.defaultBranch\n        GIT_CONFIG_VALUE_0: ${{github.event.repository.default_branch}}\n      uses: actions/checkout@v6\n      with:\n        # Include all history & tags for Scripts/version\n        fetch-depth: 0\n\n    - name: 🔧 Setup repo\n      run: Scripts/setup_workflow_repo\n\n    - name: 🛠 Select Xcode version\n      if: matrix.xcode != 'brew'\n      run: xcodes select ${{matrix.xcode}}\n\n    - name: 👢 Bootstrap\n      run: Scripts/bootstrap\n\n    - name: 🕊 Use Homebrew Core Swift\n      if: matrix.xcode == 'brew'\n      run: |\n        brew install swift\n        printf $'%s\\n' \"$(brew --prefix swift)/bin\" >> \"${GITHUB_PATH}\"\n\n    - name: 🏗 Build\n      run: Scripts/build build-test -c release\n\n    - name: 🧪 Test\n      if: matrix.xcode != 'brew'\n      run: Scripts/test\n\n    - name: 🚨 Lint\n      if: matrix.xcode != 'brew'\n      run: Scripts/lint\n"
  },
  {
    "path": ".github/workflows/codeql.yaml",
    "content": "#\n# .github/workflows/codeql.yaml\n#\n---\nname: CodeQL\non:\n  push:\n    branches: [main]\n  pull_request:\n    branches: [main]\n  schedule:\n  - cron: 44 14 * * 4\n  workflow_dispatch: {}\njobs:\n  analyze:\n    name: Analyze ${{matrix.language}}\n    runs-on: macos-26\n    permissions:\n      security-events: write\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n        - language: actions\n          build-mode: none\n        - language: swift\n          build-mode: manual\n    steps:\n    - name: 🛒 Checkout repo\n      env:\n        GIT_CONFIG_COUNT: 1\n        GIT_CONFIG_KEY_0: init.defaultBranch\n        GIT_CONFIG_VALUE_0: ${{github.event.repository.default_branch}}\n      uses: actions/checkout@v6\n      with:\n        # Include all history & tags for Scripts/version\n        fetch-depth: 0\n\n    - name: 🔧 Setup repo\n      run: Scripts/setup_workflow_repo\n\n    - name: 🔩 Initialize CodeQL\n      uses: github/codeql-action/init@v4\n      with:\n        languages: ${{matrix.language}}\n        build-mode: ${{matrix.build-mode}}\n        queries: ${{matrix.language == 'swift' && '+security-and-quality' || ''}}\n\n    - name: 🏗 Build Swift\n      if: matrix.language == 'swift'\n      shell: bash\n      run: |\n        xcodes select\n        Scripts/build codeql -c release\n\n    - name: 🔍 Perform CodeQL analysis\n      uses: github/codeql-action/analyze@v4\n      with:\n        category: /language:${{matrix.language}}\n"
  },
  {
    "path": ".github/workflows/release-published.yaml",
    "content": "#\n# .github/workflows/release-published.yaml\n#\n---\nname: release-published\non:\n  release:\n    types: [published]\npermissions:\n  actions: read\n  contents: write\n  pull-requests: write\ndefaults:\n  run:\n    # Force all run commands to not use Rosetta 2\n    shell: arch -arm64 /bin/zsh -Negku {0}\njobs:\n  release-published:\n    if: ${{!github.event.repository.fork}}\n    runs-on: macos-26\n    steps:\n    - name: 🛒 Checkout repo\n      env:\n        GIT_CONFIG_COUNT: 1\n        GIT_CONFIG_KEY_0: init.defaultBranch\n        GIT_CONFIG_VALUE_0: ${{github.event.repository.default_branch}}\n      uses: actions/checkout@v6\n      with:\n        # Include all history & tags for Scripts/version\n        fetch-depth: 0\n\n    - name: 🔧 Setup repo\n      run: Scripts/setup_workflow_repo\n\n    - name: 🚰 Apply pr-pull label to tap formula bump PR\n      env:\n        TOKEN_APP_ID: ${{secrets.TOKEN_APP_ID}}\n        TOKEN_APP_INSTALLATION_ID: ${{secrets.TOKEN_APP_INSTALLATION_ID}}\n        TOKEN_APP_PRIVATE_KEY: ${{secrets.TOKEN_APP_PRIVATE_KEY}}\n      run: |\n        export GH_TOKEN=\"$(Scripts/generate_token)\"\n\n        unsetopt errexit\n        bump_url=\"$(gh release -R \"${GITHUB_REPOSITORY}\" download \"${GITHUB_REF_NAME}\" -p bump.url -O - 2>/dev/null)\"\n        found_bump_url=\"${?}\"\n        setopt errexit\n\n        if [[ \"${found_bump_url}\" -eq 0 ]]; then\n          [[ -n \"${bump_url}\" ]] && gh pr edit \"${bump_url}\" --add-label pr-pull\n          gh release -R \"${GITHUB_REPOSITORY}\" delete-asset \"${GITHUB_REF_NAME}\" bump.url -y\n        else\n          printf $'No tap formula bump PR URL found for tag %s\\n' \"${GITHUB_REF_NAME}\"\n        fi\n"
  },
  {
    "path": ".github/workflows/tag-pushed.yaml",
    "content": "#\n# .github/workflows/tag-pushed.yaml\n#\n---\nname: tag-pushed\non:\n  push:\n    tags: ['**']\npermissions:\n  contents: write\ndefaults:\n  run:\n    # Force all run commands to not use Rosetta 2\n    shell: arch -arm64 /bin/zsh -Negku {0}\njobs:\n  tag-pushed:\n    if: ${{!github.event.repository.fork}}\n    runs-on: macos-26\n    steps:\n    - name: 🛒 Checkout repo\n      env:\n        GIT_CONFIG_COUNT: 1\n        GIT_CONFIG_KEY_0: init.defaultBranch\n        GIT_CONFIG_VALUE_0: ${{github.event.repository.default_branch}}\n      uses: actions/checkout@v6\n      with:\n        # Include all history & tags for Scripts/version\n        fetch-depth: 0\n\n    - name: 🔧 Setup repo\n      run: Scripts/setup_workflow_repo\n\n    - name: 🖋 Delete tag lacking valid signature\n      run: |\n        git fetch --force origin \"${GITHUB_REF}:${GITHUB_REF}\"\n        if [[\\\n         \"$(git cat-file tag \"${GITHUB_REF_NAME}\")\" != *'-----BEGIN SSH SIGNATURE-----'*'-----END SSH SIGNATURE-----'\\\n         ]]; then\n          printf $'Error: Deleting tag %s because it does not have a valid signature\\n' \"${GITHUB_REF_NAME}\" >&2\n          git push -d origin \"${GITHUB_REF_NAME}\"\n          exit 1\n        fi\n\n    - name: 🏷 Exit if not a version tag\n      run: |\n        if [[ ! \"${GITHUB_REF_NAME}\" =~ '^v[[:digit:]]+(\\.[[:digit:]]+)*(-(alpha|beta|rc)\\.[[:digit:]]+)?$' ]]; then\n          printf $'Exiting because %s is not a version tag\\n' \"${GITHUB_REF_NAME}\"\n          exit 2\n        fi\n\n    - name: 🌳 Delete version tag not on default branch\n      env:\n        DEFAULT_BRANCH_NAME: ${{github.event.repository.default_branch}}\n      run: |\n        git fetch --force origin \"${DEFAULT_BRANCH_NAME}:${DEFAULT_BRANCH_NAME}\"\n        if ! git merge-base --is-ancestor \"${GITHUB_REF_NAME}\" \"${DEFAULT_BRANCH_NAME}\"; then\n          printf $'Error: Deleting version tag %s because it is not on the %s branch\\n' \"${GITHUB_REF_NAME}\"\\\n           \"${DEFAULT_BRANCH_NAME}\" >&2\n          git push -d origin \"${GITHUB_REF_NAME}\"\n          exit 3\n        fi\n\n    - name: 🛠 Select Xcode version\n      run: xcodes select\n\n    - name: 📦 Build Apple & Intel installers\n      run: |\n        Scripts/package package --arch arm64\n        Scripts/package package --arch x86_64\n\n    - name: 🚰 Bump tap formula\n      env:\n        TOKEN_APP_ID: ${{secrets.TOKEN_APP_ID}}\n        TOKEN_APP_INSTALLATION_ID: ${{secrets.TOKEN_APP_INSTALLATION_ID}}\n        TOKEN_APP_PRIVATE_KEY: ${{secrets.TOKEN_APP_PRIVATE_KEY}}\n      run: |\n        export HOMEBREW_GITHUB_API_TOKEN=\"$(Scripts/generate_token)\"\n\n        brew tap \"${GITHUB_REPOSITORY_OWNER}/tap\"\n\n        unsetopt errexit\n        bump_output=\"$(brew bump-formula-pr\\\n         --tag \"${GITHUB_REF_NAME}\"\\\n         --revision \"${GITHUB_SHA}\"\\\n         --no-fork\\\n         --no-browse\\\n         --online\\\n         --strict\\\n         --verbose\\\n         \"${GITHUB_REPOSITORY_OWNER}/tap/mas\"\\\n         2>&1)\"\n        exit_status=\"${?}\"\n        setopt errexit\n\n        printf %s \"${bump_output}\"\n        printf %s \"${${(f)bump_output}[-1]}\" > .build/bump.url\n\n        exit \"${exit_status}\"\n\n    - name: 📝 Create draft release\n      env:\n        GH_TOKEN: ${{github.token}}\n      run: |\n        gh release create\\\n         \"${GITHUB_REF_NAME}\"\\\n         \".build/mas-${GITHUB_REF_NAME#v}-arm64.pkg\"\\\n         \".build/mas-${GITHUB_REF_NAME#v}-x86_64.pkg\"\\\n         .build/bump.url\\\n         -d\\\n         ${\"${GITHUB_REF_NAME//[^-]}\":+-p}\\\n         -t \"${GITHUB_REF_NAME}: ${$(git tag -l \"${GITHUB_REF_NAME}\" --format='%(contents)')%%$'\\n'*}\"\\\n         --generate-notes\n"
  },
  {
    "path": ".gitignore",
    "content": "/.build/\n/.idea/\n/.swiftpm/\n/.vscode/\n.DS_Store\n*~\n"
  },
  {
    "path": ".markdownlint-cli2.yaml",
    "content": "# yamllint disable-line rule:line-length\n# yaml-language-server: $schema=https://raw.githubusercontent.com/DavidAnson/markdownlint-cli2/main/schema/markdownlint-cli2-config-schema.json\n#\n# .markdownlint-cli2.yaml\n# mas\n#\n# markdownlint-cli2 0.21.0 / markdownlint 0.40.0\n#\n---\ngitignore: true\nnoBanner: true\nnoProgress: true\nconfig:\n  blanks-around-fences:\n    list_items: false\n  code-block-style:\n    style: fenced\n  code-fence-style:\n    style: backtick\n  emphasis-style:\n    style: underscore\n  fenced-code-language:\n    allowed_languages: [console, shell]\n    language_only: true\n  heading-style:\n    style: atx\n  hr-style:\n    style: ---\n  line-length:\n    stern: true\n  link-image-style:\n    shortcut: false\n    url_inline: false\n  no-hard-tabs:\n    code_blocks: false\n    spaces_per_tab: 2\n  no-inline-html:\n    allowed_elements: [details, h1, summary]\n  no-trailing-spaces:\n    code_blocks: true\n    strict: true\n  ol-prefix:\n    style: ordered\n  proper-names:\n    names: [mas]\n  reference-links-images:\n    shortcut_syntax: true\n  strong-style:\n    style: asterisk\n  table-column-style:\n    style: aligned\n  table-pipe-style:\n    style: leading_and_trailing\n  ul-style:\n    style: dash\n"
  },
  {
    "path": ".periphery.yaml",
    "content": "#\n# .periphery.yaml\n# mas\n#\n# Periphery 3.6.0\n#\n---\ncolor: always\ndisable_update_check: true\nquiet: true\nrelative_results: true\nstrict: true\nsuperfluous_ignore_comments: false\n"
  },
  {
    "path": ".swift-version",
    "content": "6.2\n"
  },
  {
    "path": ".swiftformat",
    "content": "#\n# .swiftformat\n# mas\n#\n# SwiftFormat 0.60.1\n#\n\n# Disabled rules (enabled by default)\n--disable hoistAwait\n--disable hoistTry\n\n# Disabled rules (disabled by default)\n#--enable blankLineAfterSwitchCase\n#--enable markTypes\n#--enable preferExplicitFalse\n#--enable testSuiteAccessControl\n\n# Enabled rules (disabled by default)\n--enable acronyms\n--enable blankLinesAfterGuardStatements\n--enable blockComments\n--enable isEmpty\n--enable noExplicitOwnership\n--enable noGuardInTests\n--enable organizeDeclarations\n--enable preferFinalClasses\n--enable preferSwiftTesting\n--enable privateStateVariables\n--enable propertyTypes\n--enable singlePropertyPerLine\n--enable sortSwitchCases\n--enable unusedPrivateDeclarations\n--enable urlMacro\n--enable validateTestCases\n--enable wrapConditionalBodies\n--enable wrapEnumCases\n--enable wrapMultilineConditionalAssignment\n--enable wrapMultilineFunctionChains\n--enable wrapSwitchCases\n\n# Rule options\n--acronyms ADAM,ADI,AE,ANSI,API,CD,CEO,CF,CI,CK,CPU,DAV,DOS,DS,DSID,DVD,EOF,FAQ,FAT,FD,FTP,GB,GID,GUI,GUID,HTML,HTTP,HTTPS,ID,IFS,ISO,JSON,KB,MAS,MD,MDM,MDS,MIB,MIT,NS,OS,OSX,PDF,PR,QL,SB,SDK,SHA,SS,SSH,STDQ,STDRDL,UDF,UI,UID,URL,US,UTF,UUID,VPP,XML,XPC,YAML\n--allow-partial-wrapping false\n--complex-attributes prev-line\n--computed-var-attributes prev-line\n--conditional-assignment always\n--exponent-grouping enabled\n--file-macro \"#fileID\"\n--fraction-grouping enabled\n--func-attributes prev-line\n--header //\\n// {file}\\n// mas\\n//\\n// Copyright © {created.year} mas-cli\\. All rights reserved\\.\\n//\n--hex-literal-case lowercase\n--ifdef no-indent\n--import-grouping alpha\n--indent tab\n--indent-strings true\n--line-after-marks false\n--mark-categories false\n--max-width 120\n--organization-mode type\n--organize-types actor,class,enum,extension,struct\n--property-types inferred\n--ranges no-space\n--redundant-async always\n--redundant-throws always\n--semicolons never\n--short-optionals always\n--single-line-for-each convert\n--stored-var-attributes prev-line\n--tab-width 2\n--timezone utc\n--type-attributes prev-line\n--type-body-marks remove\n--wrap-arguments before-first\n--wrap-collections before-first\n--wrap-conditions before-first\n--wrap-effects never\n--wrap-parameters before-first\n--wrap-return-type never\n--wrap-ternary before-operators\n--wrap-type-aliases before-first\n"
  },
  {
    "path": ".swiftlint.yml",
    "content": "#\n# .swiftlint.yml\n# mas\n#\n# SwiftLint 0.63.2\n#\n---\nexcluded:\n- .build/\n- .idea/\n- .swiftpm/\n- .vscode/\nopt_in_rules:\n- all\nanalyzer_rules:\n- all\ndisabled_rules:\n- closure_body_length\n- contrasted_opening_brace\n- cyclomatic_complexity\n- explicit_acl\n- explicit_enum_raw_value\n- explicit_self\n- explicit_top_level_acl\n- explicit_type_interface\n- file_header\n- function_body_length\n- large_tuple\n- multiple_closures_with_trailing_closure\n- no_extension_access_modifier\n- no_grouping_extension\n- no_magic_numbers\n- prefixed_toplevel_constant\n- strict_fileprivate\n- type_body_length\nattributes:\n  always_on_line_above: ['@Flag', '@MainActor', '@OptionGroup']\ndeployment_target:\n  macOS_deployment_target: 13\n  macOSApplicationExtension_deployment_target: 13\n  iOS_deployment_target: 99\n  iOSApplicationExtension_deployment_target: 99\n  tvOS_deployment_target: 99\n  tvOSApplicationExtension_deployment_target: 99\n  watchOS_deployment_target: 99\n  watchOSApplicationExtension_deployment_target: 99\nfile_length:\n  ignore_comment_only_lines: true\n  warning: 500\nfile_name:\n  excluded: [Group.swift, InstalledApp+Spotlight.swift, Process.swift, User.swift]\nfile_types_order:\n  order:\n  - main_type\n  - supporting_type\n  - extension\n  - preview_provider\n  - library_content_provider\nfunction_parameter_count:\n  warning: 6\nindentation_width:\n  indentation_width: 2\n  include_multiline_strings: false\nline_length:\n  ignores_multiline_strings: true\n  ignores_regex_literals: true\nmodifier_order:\n  preferred_modifier_order:\n  - acl\n  - setterACL\n  - override\n  - isolation\n  - dynamic\n  - mutators\n  - lazy\n  - final\n  - required\n  - convenience\n  - typeMethods\n  - owned\nmultiline_arguments:\n  first_argument_location: next_line\nnon_optional_string_data_conversion:\n  include_variables: true\nnumber_separator:\n  minimum_length: 6\nopening_brace:\n  ignore_multiline_statement_conditions: true\noperator_usage_whitespace:\n  skip_aligned_constants: false\nprefer_key_path:\n  restrict_to_standard_functions: false\nprivate_over_fileprivate:\n  validate_extensions: true\nredundant_self:\n  only_in_closures: false\nredundant_type_annotation:\n  consider_default_literal_types_redundant: true\ntrailing_comma:\n  mandatory_comma: true\ntrailing_whitespace:\n  ignores_comments: false\ntype_contents_order:\n  order:\n  - case\n  - associated_type\n  - type_alias\n  - subtype\n  - type_property\n  - instance_property\n  - ib_inspectable\n  - ib_outlet\n  - initializer\n  - deinitializer\n  - type_method\n  - view_life_cycle_method\n  - ib_action\n  - other_method\n  - subscript\nunneeded_override:\n  affect_initializers: true\nunused_import:\n  require_explicit_imports: true\n  allowed_transitive_imports:\n  - module: Darwin\n    allowed_transitive_imports:\n    - _DarwinFoundation1\n    - _DarwinFoundation2\n    - _DarwinFoundation3\n  - module: Swift\n    allowed_transitive_imports:\n    - _Concurrency\n    - _StringProcessing\nvertical_whitespace_between_cases:\n  separation: never\n"
  },
  {
    "path": ".xcode-version",
    "content": "26.3\n"
  },
  {
    "path": ".yamllint.yaml",
    "content": "#\n# .yamllint.yaml\n# mas\n#\n# yamllint 1.38.0\n#\n---\nextends: default\nlocale: en_US.UTF-8\nignore-from-file: .gitignore\nrules:\n  anchors:\n    forbid-duplicated-anchors: true\n    forbid-undeclared-aliases: true\n    forbid-unused-anchors: true\n  braces:\n    forbid: non-empty\n    max-spaces-inside-empty: 0\n  brackets:\n    forbid: false\n    max-spaces-inside: 0\n    max-spaces-inside-empty: 0\n  colons:\n    max-spaces-before: 0\n    max-spaces-after: 1\n  commas:\n    max-spaces-before: 0\n    min-spaces-after: 1\n    max-spaces-after: 1\n  comments:\n    require-starting-space: true\n    min-spaces-from-content: 1\n  comments-indentation: enable\n  document-end:\n    present: false\n  document-start:\n    present: true\n  empty-lines:\n    max: 2\n    max-start: 0\n    max-end: 0\n  empty-values:\n    forbid-in-block-mappings: true\n    forbid-in-block-sequences: true\n    forbid-in-flow-mappings: true\n  float-values:\n    require-numeral-before-decimal: true\n  hyphens:\n    max-spaces-after: 1\n  indentation:\n    spaces: 2\n    indent-sequences: false\n    check-multi-line-strings: false\n  key-duplicates:\n    forbid-duplicated-merge-keys: true\n  key-ordering: disable\n  line-length:\n    max: 120\n    allow-non-breakable-inline-mappings: true\n  new-line-at-end-of-file: enable\n  new-lines:\n    type: unix\n  octal-values:\n    forbid-implicit-octal: true\n    forbid-explicit-octal: true\n  quoted-strings:\n    check-keys: true\n    required: only-when-needed\n    quote-type: single\n  trailing-spaces: enable\n  truthy:\n    check-keys: false\n    allowed-values: ['true', 'false']\n"
  },
  {
    "path": "Brewfile",
    "content": "brew \"actionlint\"        # 1.7.11\nbrew \"gh\"                # 2.87.3\nbrew \"git\"               # 2.53.0\nbrew \"ipsw\"              # 3.1.660\nbrew \"markdownlint-cli2\" # 0.21.0\nbrew \"periphery\" if MacOS.version >= :sequoia && `/usr/bin/arch` == \"arm64\" # 3.6.0\nbrew \"shellcheck\"        # 0.11.0\nbrew \"swiftformat\"       # 0.60.1\nbrew \"swiftlint\"         # 0.63.2\nbrew \"xcodes\"            # 1.6.2\nbrew \"yamllint\"          # 1.38.0\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open & welcoming environment, we as contributors\n& maintainers pledge to making participation in our project & our community a\nharassment-free experience for everyone, regardless of age, body size,\ndisability, ethnicity, sex characteristics, gender identity & expression, level\nof experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity & orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n- Using welcoming & inclusive language\n- Being respectful of differing viewpoints & experiences\n- Gracefully accepting constructive criticism\n- Focusing on what is best for the community\n- Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n- The use of sexualized language or imagery & unwelcome sexual attention or\n advances\n- Trolling, insulting/derogatory comments, & personal or political attacks\n- Public or private harassment\n- Publishing others' private information, such as a physical or electronic\n address, without explicit permission\n- Other conduct which could reasonably be considered inappropriate in a\n professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior & are expected to take appropriate & fair corrective action in response\nto any instances of unacceptable behavior.\n\nProject maintainers have the right & responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, & other contributions that are not\naligned to this Code of Conduct, or to temporarily or permanently ban any\ncontributor for other behaviors that they deem inappropriate, threatening,\noffensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces & in public spaces when\nan individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined & clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at @mas-cli/admins. All complaints will\nbe reviewed & investigated & will result in a response that is deemed necessary\n& appropriate to the circumstances. The project team is obligated to maintain\nconfidentiality with regard to the reporter of an incident. Further details of\nspecific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the\n[Contributor Covenant version 1.4](\n  https://www.contributor-covenant.org/version/1/4/code-of-conduct/\n).\n\nFor answers to common questions about this Code of Conduct, see\nthe [Contributor Covenant FAQ](https://www.contributor-covenant.org/faq/).\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nPull requests (PRs) are welcome from everyone.\n\nBy participating in this project, you agree to abide by the\n[code of conduct](CODE_OF_CONDUCT.md).\n\n## Getting Started\n\n- Ensure you have a [GitHub account](https://github.com/signup)\n- [Search for similar issues](https://github.com/mas-cli/mas/issues)\n- If one doesn't exist,\n  [open a new issue](https://github.com/mas-cli/mas/issues/new/choose)\n  - Select the appropriate issue template\n  - Follow the instructions in the issue template\n\n## Making Changes\n\nThis project uses [trunk-based development](https://trunkbaseddevelopment.com),\nwhere `main` is the trunk.\n\n- [Fork the repository](https://github.com/mas-cli/mas#fork-button) on\n  GitHub\n- Clone your fork: `git clone git@github.com:your-username/mas.git`\n- Create a topic branch instead of [working directly on `main`](\n    https://softwareengineering.stackexchange.com/questions/223400/when-should-i-stop-committing-to-master-on-new-projects\n  )\n  - To branch a topic branch from `main` named, e.g., `feature`, run:\n    `git checkout -b feature main`\n- Commit logical units\n- Follow the [style guide](Documentation/style.md)\n- Run `Scripts/format` before committing\n- Run `Scripts/lint` before committing, then fix all lint violations\n- Write tests\n  - If you need help with tests, feel free to open a PR, then ask for help\n- Write [good commit messages](\n    https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html\n  )\n- Push your topic branch to your fork, then submit a pull request (PR)\n  - If your PR is not ready to be merged, create a draft PR\n\n## Releases\n\n- Release commits are tagged in the format of `v1.2.3`\n- Releases (including release notes) are published on the\n  [Releases page](https://github.com/mas-cli/mas/releases)\n\n## Becoming a Contributor\n\nTo join the [team](https://github.com/orgs/mas-cli/teams/contributors), once a\nfew of your PRs have been accepted,\n[open an issue](https://github.com/mas-cli/mas/issues/new) titled\n\"Add Contributor: @YourGitHubUsername\".\n\nThis project was created by [@argon](https://github.com/argon), who is unable to\ncontinue contributing to this project, but must remain an owner.\n\nBy becoming a contributor, you agree to the following terms:\n\n- Do not claim to be the original author\n- Retain [@argon](https://github.com/argon)'s name in the license; others' names\n  may be added to it after they have made substantial contributions\n- Retain [@argon](https://github.com/argon)'s name (Andrew Naylor),\n  [GitHub account](https://github.com/argon) & [X handle](https://x.com/argon)\n  in the [README](README.md), though they may be repositioned as deemed suitable\n\n## Project Lead Responsibilities\n\nProject leads agree to the following terms:\n\n- [@argon](https://github.com/argon) must continue to be one of the organization\n  owners\n- Project leads have full control, however, over the project's future direction\n- If you are the sole project lead, but can no longer lead the project, either:\n  - Find someone else to assume the project leadership who agrees to adhere to,\n    & propagate, the existing terms\n  - If you cannot find a new project lead:\n    - Add an [unmaintained badge](https://unmaintained.tech) to the\n      [README](README.md)\n    - Message [@argon](https://github.com/argon) via [X](https://x.com/argon) or\n      [email](mailto:argon@mkbot.net)\n    - Transfer the project back to [@argon](https://github.com/argon)\n"
  },
  {
    "path": "Documentation/Sample.swift",
    "content": "//\n// Sample.swift\n// mas\n//\n// Copyright © 2018 mas-cli. All rights reserved.\n//\n\n// MARK: Types & naming\n\n/// The first letter of a type should be uppercase.\n///\n/// Prefer structs. When a class is necessary, default to making it `final`.\nfinal class Sample {\n\tlet name: String\n\n\t/// If the first letter of an acronym is lowercase, the entire thing should be\n\t/// lowercase.\n\tlet json: Any\n\n\tdeinit {\n\t\t// Clean up resources\n\t}\n\n\t/// If the first letter of an acronym is uppercase, the entire thing should be\n\t/// uppercase.\n\tstatic func decode(from json: JSON) -> Self {\n\t\t.init(json: json)\n\t}\n}\n\n/// Use `()` for void arguments & `Void` for void return types.\nlet closure: () -> Void = {\n\t// Do nothing\n}\n\n/// Use `typealias` when closures are referenced in multiple places.\ntypealias CoolClosure = (Int) -> Bool\n\n/// Use aliased parameter names when function parameters are ambiguous.\nfunc yTown(some: Int, withCallback callback: CoolClosure) -> Bool {\n\tcallback(some)\n}\n\n/// Use `$` variable references if the closure fits on one line.\nlet cool = yTown(5) { $0 == 6 }\n\n/// Use explicit variable names if the closure is on multiple lines.\nlet cool = yTown(5) { foo in\n\tmax(foo, 0)\n\t// …\n}\n\n// Strongify weak references in async closures\nAPIClient.getAwesomeness { [weak self] result in\n\tguard let self else {\n\t\treturn\n\t}\n\n\tstopLoadingSpinner()\n\tshow(result)\n}\n\n/// Use if-let to check for not `nil` (even if using an implicitly unwrapped\n/// variable from an API).\nfunc someUnauditedAPI(thing: String?) {\n\tif let thing {\n\t\tprinter.info(thing)\n\t}\n}\n\n/// Infer variable types instead of explicitly declaring them.\nlet response = Response.success(Data())\n\nfunc doSomeWork() -> Response {\n\tlet data = Data(\"\", .utf8)\n\treturn .success(data)\n}\n\nswitch response {\ncase let .success(data):\n\tprinter.info(\"The response returned successfully\", data)\ncase let .failure(error):\n\tprinter.error(\"An error occurred:\", error: error)\n}\n\n// MARK: Organization\n\n/// Group methods into specific extensions for each level of access control.\nprivate extension MyClass {\n\tfunc doSomethingPrivate() {\n\t\t// Do something\n\t}\n}\n\n// MARK: Breaking up long lines\n\n// If a guard clause requires multiple lines, chop it down, then start the else\n// clause on a new line\nguard\n\tlet oneItem = somethingFailable(),\n\tlet secondItem = somethingFailable2()\nelse {\n\treturn\n}\n"
  },
  {
    "path": "Documentation/style.md",
    "content": "# All Files\n\n- Before committing, run `Scripts/lint` to detect linting violations\n- Run `Scripts/format` to automatically fix many linting violations\n- Remove unnecessary trailing whitespace\n  - Note that 2 trailing spaces is valid Markdown to create a line break like\n    `<br>`, so those should _not_ be removed\n- End each file with a [single newline character](\n    https://unix.stackexchange.com/questions/18743/whats-the-point-in-adding-a-new-line-to-the-end-of-a-file#18789\n  )\n\n## Swift\n\n[Sample](Sample.swift)\n\n- Avoid [force unwrapping optionals](\n    https://blog.timac.org/2017/0628-swift-banning-force-unwrapping-optionals\n  ) with `!` in production code\n  - Production code is located under the [`Sources/mas`](\n      https://github.com/mas-cli/mas/tree/main/Sources/mas\n    ) folder\n  - However, force unwrapping is **encouraged** in tests for concision; tests\n    _should_ break when any expected conditions aren't met\n- Prefer `struct`s over `class`es wherever possible\n- Default to marking classes as `final`\n- Prefer composition over protocol conformance over class inheritance\n- Break lines at 120 characters\n- Use tabs for indentation\n- Use `let` whenever possible to make immutable bindings\n- Name most parameters in functions & enum cases\n- Use trailing closures\n- Let the compiler infer the type whenever possible\n- Group computed properties below stored properties\n- Use a blank line above & below computed properties\n- Apply the capitalization of the first letter throughout an acronym or\n  initialism\n- Use `()` for void arguments & `Void` for void return types\n- Strongify weak references instead of evaluating them multiple times\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Andrew Naylor, Ross Goldberg\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "Package.resolved",
    "content": "{\n\t\"originHash\" : \"fe336dc5a91893be96812ec91baba97112f3407b3c398b918ac3eeebc5bc9781\",\n\t\"pins\" : [\n\t\t{\n\t\t\t\"identity\" : \"bigint\",\n\t\t\t\"kind\" : \"remoteSourceControl\",\n\t\t\t\"location\" : \"https://github.com/attaswift/BigInt.git\",\n\t\t\t\"state\" : {\n\t\t\t\t\"revision\" : \"e07e00fa1fd435143a2dcf8b7eec9a7710b2fdfe\",\n\t\t\t\t\"version\" : \"5.7.0\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"identity\" : \"chronometer\",\n\t\t\t\"kind\" : \"remoteSourceControl\",\n\t\t\t\"location\" : \"https://github.com/KittyMac/Chronometer.git\",\n\t\t\t\"state\" : {\n\t\t\t\t\"revision\" : \"99d4f4137837a28e1e294eb69ac66ad53c0934d3\",\n\t\t\t\t\"version\" : \"0.1.14\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"identity\" : \"hitch\",\n\t\t\t\"kind\" : \"remoteSourceControl\",\n\t\t\t\"location\" : \"https://github.com/KittyMac/Hitch.git\",\n\t\t\t\"state\" : {\n\t\t\t\t\"revision\" : \"d3bfe4b90303653d71f5423c6ec2cbe47b75d7ed\",\n\t\t\t\t\"version\" : \"0.4.151\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"identity\" : \"sextant\",\n\t\t\t\"kind\" : \"remoteSourceControl\",\n\t\t\t\"location\" : \"https://github.com/KittyMac/Sextant.git\",\n\t\t\t\"state\" : {\n\t\t\t\t\"revision\" : \"d4f794ac57a84dadacd1a0edd5d29717ef0e7b74\",\n\t\t\t\t\"version\" : \"0.4.38\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"identity\" : \"spanker\",\n\t\t\t\"kind\" : \"remoteSourceControl\",\n\t\t\t\"location\" : \"https://github.com/KittyMac/Spanker.git\",\n\t\t\t\"state\" : {\n\t\t\t\t\"revision\" : \"ff05ac41aea633ca7a9fd966d3164373247ee8dd\",\n\t\t\t\t\"version\" : \"0.2.53\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"identity\" : \"swift-argument-parser\",\n\t\t\t\"kind\" : \"remoteSourceControl\",\n\t\t\t\"location\" : \"https://github.com/apple/swift-argument-parser.git\",\n\t\t\t\"state\" : {\n\t\t\t\t\"revision\" : \"c5d11a805e765f52ba34ec7284bd4fcd6ba68615\",\n\t\t\t\t\"version\" : \"1.7.0\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"identity\" : \"swift-atomics\",\n\t\t\t\"kind\" : \"remoteSourceControl\",\n\t\t\t\"location\" : \"https://github.com/apple/swift-atomics.git\",\n\t\t\t\"state\" : {\n\t\t\t\t\"revision\" : \"b601256eab081c0f92f059e12818ac1d4f178ff7\",\n\t\t\t\t\"version\" : \"1.3.0\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"identity\" : \"swift-collections\",\n\t\t\t\"kind\" : \"remoteSourceControl\",\n\t\t\t\"location\" : \"https://github.com/apple/swift-collections.git\",\n\t\t\t\"state\" : {\n\t\t\t\t\"revision\" : \"8d9834a6189db730f6264db7556a7ffb751e99ee\",\n\t\t\t\t\"version\" : \"1.4.0\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"identity\" : \"swiftsoup\",\n\t\t\t\"kind\" : \"remoteSourceControl\",\n\t\t\t\"location\" : \"https://github.com/scinfu/SwiftSoup.git\",\n\t\t\t\"state\" : {\n\t\t\t\t\"revision\" : \"dba183c96b2da4e4b80bb31b1e2e59cb9542b8fc\",\n\t\t\t\t\"version\" : \"2.13.0\"\n\t\t\t}\n\t\t}\n\t],\n\t\"version\" : 3\n}\n"
  },
  {
    "path": "Package.swift",
    "content": "// swift-tools-version:6.2\n\nprivate import PackageDescription\n\nprivate let swiftSettings = [\n\tSwiftSetting\n\t.enableUpcomingFeature(\"ExistentialAny\"), // swiftformat:disable:this indent\n\t.enableUpcomingFeature(\"ImmutableWeakCaptures\"),\n\t.enableUpcomingFeature(\"InferIsolatedConformances\"),\n\t.enableUpcomingFeature(\"InternalImportsByDefault\"),\n\t.enableUpcomingFeature(\"MemberImportVisibility\"),\n\t.enableUpcomingFeature(\"NonisolatedNonsendingByDefault\"),\n\t.treatAllWarnings(as: .error),\n]\n\n_ = Package(\n\tname: \"mas\",\n\tplatforms: [.macOS(.v13)],\n\tproducts: [.executable(name: \"mas\", targets: [\"mas\"])],\n\tdependencies: [\n\t\t.package(url: \"https://github.com/KittyMac/Sextant.git\", from: \"0.4.38\"),\n\t\t.package(url: \"https://github.com/apple/swift-argument-parser.git\", from: \"1.7.0\"),\n\t\t.package(url: \"https://github.com/apple/swift-atomics.git\", from: \"1.3.0\"),\n\t\t.package(url: \"https://github.com/apple/swift-collections.git\", from: \"1.4.0\"),\n\t\t.package(url: \"https://github.com/attaswift/BigInt.git\", from: \"5.7.0\"),\n\t\t.package(url: \"https://github.com/scinfu/SwiftSoup.git\", from: \"2.13.0\"),\n\t],\n\ttargets: [\n\t\t.plugin(name: \"MASBuildToolPlugin\", capability: .buildTool()),\n\t\t.target(name: \"PrivateFrameworks\"),\n\t\t.executableTarget(\n\t\t\tname: \"mas\",\n\t\t\tdependencies: [\n\t\t\t\t.product(name: \"ArgumentParser\", package: \"swift-argument-parser\"),\n\t\t\t\t.product(name: \"Atomics\", package: \"swift-atomics\"),\n\t\t\t\t.product(name: \"OrderedCollections\", package: \"swift-collections\"),\n\t\t\t\t\"BigInt\",\n\t\t\t\t\"PrivateFrameworks\",\n\t\t\t\t\"Sextant\",\n\t\t\t\t\"SwiftSoup\",\n\t\t\t],\n\t\t\tswiftSettings: swiftSettings,\n\t\t\tlinkerSettings: [.unsafeFlags([\"-F\", \"/System/Library/PrivateFrameworks\"])],\n\t\t\tplugins: [.plugin(name: \"MASBuildToolPlugin\")],\n\t\t),\n\t\t.testTarget(\n\t\t\tname: \"MASTests\",\n\t\t\tdependencies: [\"mas\"],\n\t\t\tresources: [.process(\"Resources\")],\n\t\t\tswiftSettings: swiftSettings,\n\t\t),\n\t],\n\tswiftLanguageModes: [.v6],\n)\n"
  },
  {
    "path": "Plugins/MASBuildToolPlugin/MASBuildToolPlugin.swift",
    "content": "//\n// MASBuildToolPlugin.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\nprivate import Foundation\ninternal import PackagePlugin\n\n@main\nstruct MASBuildToolPlugin: BuildToolPlugin {\n\tfunc createBuildCommands(context: PluginContext, target _: any Target) -> [Command] {\n\t\t[\n\t\t\t.prebuildCommand(\n\t\t\t\tdisplayName: \"Prebuild mas\",\n\t\t\t\texecutable: context.package.directoryURL.appending(path: \"Scripts/prebuild\", directoryHint: .notDirectory),\n\t\t\t\targuments: [context.pluginWorkDirectoryURL.path(percentEncoded: false)],\n\t\t\t\tenvironment: ProcessInfo.processInfo.environment,\n\t\t\t\toutputFilesDirectory: context.pluginWorkDirectoryURL,\n\t\t\t),\n\t\t]\n\t}\n}\n"
  },
  {
    "path": "README.md",
    "content": "<h1 align=\"center\">\n\n![mas](mas.png)\n\n</h1>\n\n[![current release version](https://img.shields.io/github/v/release/mas-cli/mas.svg?style=for-the-badge)](https://github.com/mas-cli/mas/releases)\n[![supported OS: macOS 13+](https://img.shields.io/badge/Supported_OS-macOS_13%2B-teal?style=for-the-badge)](Package.swift)\n[![license: MIT](https://img.shields.io/badge/license-MIT-750014.svg?style=for-the-badge)](LICENSE)\n[![language: Swift 6.2](https://img.shields.io/badge/language-Swift_6.2-F05138.svg?style=for-the-badge)](https://www.swift.org)\n[![build, test & lint status](https://img.shields.io/github/actions/workflow/status/mas-cli/mas/build-test.yaml?label=build,%20test%20%26%20lint&style=for-the-badge)](\n  https://github.com/mas-cli/mas/actions/workflows/build-test.yaml?query=branch%3Amain\n)\n[![dependencies status](https://img.shields.io/librariesio/github/mas-cli/mas?style=for-the-badge)](Package.swift)\n\nmas is a command-line interface for the Mac App Store that is designed for\nscripting & automation.\n\n<details>\n<summary>\n\n## 📲 Installation\n\n</summary>\n<details>\n<summary>\n\n### 🔮 macOS 13 (Ventura) or newer\n\n</summary>\n<details>\n<summary>\n\n#### 🍺 Homebrew Core formula\n\n</summary>\n\n[Homebrew](https://brew.sh) is the preferred way to install:\n\n```shell\nbrew install mas\n```\n\n</details>\n<details>\n<summary>\n\n#### 🔌 MacPorts\n\n</summary>\n\n[MacPorts](https://www.macports.org/install.php) is an alternative way to\ninstall:\n\n```shell\nsudo port install mas\n```\n\n</details>\n</details>\n<details>\n<summary>\n\n### 🧮 macOS 10.11 (El Capitan) - 12 (Monterey)\n\n</summary>\n<details>\n<summary>\n\n#### 🍻 Homebrew tap\n\n</summary>\n\nThe [mas-cli Homebrew tap](https://github.com/mas-cli/homebrew-tap) provides\npre-built bottles for all macOS versions since 10.11 (El Capitan).\n\nThe newest versions of mas, however, are only available for macOS 13+ (Ventura\nor newer).\n\nTo install mas from the tap:\n\n```shell\nbrew install mas-cli/tap/mas\n```\n\n</details>\n<details>\n<summary>\n\n#### 🐙 GitHub Releases\n\n</summary>\n\nAlternatively, binaries & sources are available from\n[GitHub Releases](https://github.com/mas-cli/mas/releases).\n\n</details>\n</details>\n</details>\n<details>\n<summary>\n\n## 🤳 Usage\n\n</summary>\n<details>\n<summary>\n\n### 🪪 App IDs\n\n</summary>\n\nEach app in the App Store has a unique integer app identifier (ADAM ID) & a\nunique text app identifier (bundle ID). mas commands accept either form of app\nID as arguments.\n\n`mas search` & `mas list` can be used to find the ADAM IDs of apps.\n\nAlternatively, to find an app's ADAM ID:\n\n1. Find the app in the App Store\n2. Select `Share` > `Copy Link`\n3. Extract the ADAM ID from the URL\n   - e.g., extract ADAM ID `497799835` from the URL for Xcode\n     (<https://apps.apple.com/us/app/xcode/id497799835?mt=12>)\n\n</details>\n<details>\n<summary>\n\n### 🛍 Info from the App Store\n\n</summary>\n\nThe commands in this section do not require you to be logged into an Apple\nAccount, neither for your macOS user nor for the App Store.\n\n<details>\n<summary>\n\n#### `mas search`\n\n</summary>\n\n`mas search <search-term>` searches by name for apps available from the App\nStore.\n\nProviding the `--price` flag includes each app's price in the output.\n\n```console\n$ mas search Xcode\n497799835 Xcode\n688199928 Docs for Xcode\n…\n```\n\n</details>\n<details>\n<summary>\n\n#### `mas lookup`\n\n</summary>\n\n`mas lookup <app-id>` outputs more detailed information about an app available\nfrom the App Store.\n\n```console\n$ mas lookup 497799835\nXcode 26.1.1 [Free]\nBy: Apple Inc.\nReleased: 2025-11-11\nMinimum OS: 15.6\nSize: 2,913.8 MB\nFrom: https://apps.apple.com/us/app/xcode/id497799835?mt=12&uo=4\n```\n\n</details>\n</details>\n<details>\n<summary>\n\n### 📚 Info from your local app library\n\n</summary>\n\nAll the commands in this section require you to be logged into an Apple Account\nfor your macOS user.\n\n<details>\n<summary>\n\n#### `mas list`\n\n</summary>\n\n`mas list` outputs all the apps on your Mac that were installed from the App\nStore.\n\n```console\n$ mas list\n497799835 Xcode       (15.4)\n640199958 Developer   (10.6.5)\n899247664 TestFlight  (3.5.2)\n```\n\n</details>\n<details>\n<summary>\n\n#### `mas outdated`\n\n</summary>\n\n`mas outdated` outputs all apps installed from the App Store on your Mac that\nhave pending updates.\n\n```console\n$ mas outdated\n497799835 Xcode (15.4 -> 16.0)\n640199958 Developer (10.6.5 -> 10.6.6)\n```\n\nRun [`mas update`](#mas-update) to install pending updates.\n\n</details>\n</details>\n<details>\n<summary>\n\n### ⬇️ Installing apps\n\n</summary>\n\nAll the commands in this section require you to be logged into an Apple Account\nin the App Store.\n\n> Depending on your Apple Account settings, you might need to re-authenticate in\n> the App Store to perform a `get`, `install`, `lucky`, or `update`, even if you\n> are already signed in to an Apple Account in the App Store.\n\n<details>\n<summary>\n\n#### `mas get`\n\n</summary>\n\n`mas get <app-id>…` installs free apps that you haven't yet gotten/\"purchased\"\nfrom the App Store.\n\n[Requires root privileges to install apps](#-root-privileges).\n\n> The `purchase` alias is currently a misnomer, because it currently can only\n> \"purchase\" free apps. To purchase apps that cost money, purchase them directly\n> in the App Store.\n\n```console\n$ mas get 497799835\n==> Downloading Xcode\n==> Installed Xcode\n```\n\n</details>\n<details>\n<summary>\n\n#### `mas install`\n\n</summary>\n\n`mas install <app-id>…` installs apps that you have already gotten or purchased\nfrom the App Store. Providing the `--force` flag re-installs the app even if it\nis already installed on your Mac.\n\n[Requires root privileges to install apps](#-root-privileges).\n\n```console\n$ mas install 497799835\n==> Downloading Xcode\n==> Installed Xcode\n```\n\n</details>\n<details>\n<summary>\n\n#### `mas lucky`\n\n</summary>\n\n`mas lucky <search-term>` installs the first result that would be returned by\n`mas search <search-term>`. Like `mas install`, `mas lucky` can only install\napps that have previously been gotten or purchased.\n\n[Requires root privileges to install apps](#-root-privileges).\n\n```console\n$ mas lucky Xcode\n==> Downloading Xcode\n==> Installed Xcode\n```\n\n</details>\n</details>\n<details>\n<summary>\n\n### 🆕 Upgrading apps\n\n</summary>\n\nAll the commands in this section require you to be logged into an Apple Account\nin the App Store.\n\n> mas only installs/updates apps from the App Store.\n>\n> Use [`softwareupdate(8)`](https://www.unix.com/man-page/osx/8/softwareupdate)\n> to install system updates (e.g., Xcode Command Line Tools, Safari, etc.)\n\n<details>\n<summary>\n\n#### `mas update`\n\n</summary>\n\n`mas update` updates outdated apps installed from the App Store. Without any\narguments, it updates all such apps.\n\n[Requires root privileges to update apps](#-root-privileges).\n\n```console\n$ mas update\nUpgrading 2 outdated applications:\nXcode (15.4) -> (16.0)\nDeveloper (10.6.5) -> (10.6.6)\n==> Downloading Xcode\n==> Installed Xcode\n==> Downloading Developer\n==> Installed Developer\n```\n\nUpdates can be performed selectively by providing app IDs to `mas update`.\n\n```console\n$ mas update 715768417\nUpgrading 1 outdated application:\nXcode (15.4) -> (16.0)\n==> Downloading Xcode\n==> Installed Xcode\n```\n\n</details>\n</details>\n<details>\n<summary>\n\n### 🪪 App Store account management\n\n</summary>\n\nAll the commands in this section interact with the Apple Account for which you\nare signed in to the App Store. These commands do not interact with the Apple\nAccount for which your macOS user is signed in.\n\n<details>\n<summary>\n\n#### `mas signout`\n\n</summary>\n\n`mas signout` signs out from the current Apple Account in the App Store.\n\n</details>\n</details>\n<details>\n<summary>\n\n### 🫚 Root privileges\n\n</summary>\n\nRoot privileges are now necessary to install/update apps from the App Store,\nbecause Apple secured `installd` on macOS 26.1+, 15.7.2+ & 14.8.2+ to fix\n[CVE-2025-43411](https://nvd.nist.gov/vuln/detail/CVE-2025-43411). To simplify\nthe code, mas 4.0.0+ requires root privileges to install/update apps for all\nversions of macOS, even older ones for which `installd` hasn't been secured.\nMost users are already, or soon will be, using affected macOS versions.\n\nRoot privileges were always necessary to uninstall apps from the App Store,\nbecause such apps are owned by the `root` user on macOS. mas 4.0.0+ will request\nroot privileges if you run mas without them, so you needn't remember to use\n`sudo mas uninstall …` like beforehand.\n\nRoot privileges can be granted by running using `sudo mas …` on the command\nline, or, if you run `mas` by itself without `sudo`, by entering your macOS\naccount password when prompted by `mas`. If you choose the latter route, the\nsupplied password is piped directly from the terminal to an external process\n`sudo` call in the `mas` executable; your password is never seen by any mas\ncode, nor is it stored in any way.\n\nAny sudo credentials used or established by the `mas` executable will remain\nvalid, pursuant to your user-configured sudo timeout settings.\n\n</details>\n</details>\n<details>\n<summary>\n\n## 🧩 Integrations\n\n</summary>\n<details>\n<summary>\n\n### 🍻 Homebrew Bundle\n\n</summary>\n\nIf mas is installed:\n\n- `brew bundle dump` includes installed App Store apps in the generated\n  `Brewfile`\n- Homebrew Bundle commands will process App Store apps included in a `Brewfile`\n\nSee the\n[Homebrew Bundle documentation](https://docs.brew.sh/Brew-Bundle-and-Brewfile)\nfor more details.\n\n</details>\n<details>\n<summary>\n\n### ⚙️ Topgrade\n\n</summary>\n\nIf mas is installed, running [Topgrade](https://github.com/topgrade-rs/topgrade)\nupdates installed App Store apps.\n\n</details>\n</details>\n<details>\n<summary>\n\n## ⚠️ Known issues\n\n</summary>\n<details>\n<summary>\n\n### 💥 Broken Apple private frameworks\n\n</summary>\n\nmas uses multiple undocumented Apple private frameworks to implement much of its\nfunctionality.\n\nOver time, Apple has silently changed these frameworks, breaking some\nfunctionality, including:\n\n- [The `account` command is not supported on macOS 12 (Monterey) or newer](\n    https://github.com/mas-cli/mas/issues/417\n  )\n- [The `signin` command is not supported on macOS 10.13 (High Sierra) or newer](\n    https://github.com/mas-cli/mas/issues/164\n  )\n\n</details>\n<details>\n<summary>\n\n### ⏳ Eventual consistency\n\n</summary>\n\nThe App Store operates on eventual consistency.\n\n[The app versions seen by various parts of mas or the App Store might be\ninconsistent for days](https://github.com/mas-cli/mas/issues/387).\n\n</details>\n<details>\n<summary>\n\n### 📱 iOS & iPadOS apps\n\n</summary>\n\nApple Silicon Macs can install iOS & iPadOS apps from the App Store.\n\n[mas does not yet support iOS or iPadOS apps](\n  https://github.com/mas-cli/mas/issues/321\n).\n\n</details>\n<details>\n<summary>\n\n### 📺 `tmux`\n\n</summary>\n\nmas depends on the same XPC system services as the App Store.\n\nmas thus experiences similar problems as the pasteboard when running inside\n`tmux`.\n\nThis [wrapper](https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard) allows\npasteboard & mas to work inside `tmux`.\n\n`tmux` can be configured to always use the wrapper.\n\nAlternatively, the wrapper can be used on a one-off basis:\n\n```shell\nbrew install reattach-to-user-namespace\nreattach-to-user-namespace mas install\n```\n\n</details>\n<details>\n<summary>\n\n### 🤷 Undetected installed apps\n\n</summary>\n\nmas 2.0.0+ sources data for installed App Store apps from macOS's Spotlight\nMetadata Server (aka MDS).\n\nYou can check if an App Store app is properly indexed in Spotlight:\n\n```console\n## General format:\n$ mdls -rn kMDItemAppStoreAdamID <path-to-app>\n## Outputs the ADAM ID if the app is indexed\n## Outputs nothing if the app is not indexed\n\n## Example:\n$ mdls -rn kMDItemAppStoreAdamID /Applications/WhatsApp.app\n310633997\n```\n\nIf an app has been indexed in Spotlight, the path to the app can be found:\n\n```shell\nmdfind 'kMDItemAppStoreAdamID = <adam-id>'\n```\n\nIf any App Store apps are not properly indexed, you can reindex:\n\n```shell\n# Individual apps (if you know exactly what apps were incorrectly omitted):\nmdimport /Applications/Example.app\n\n# All apps (<LargeAppVolume> is the volume optionally selected for large apps):\nmdimport /Applications /Volumes/<LargeAppVolume>/Applications\n\n# All file system volumes (if neither aforementioned command solved the issue):\nsudo mdutil -Eai on\n```\n\n</details>\n</details>\n<details>\n<summary>\n\n## ❗ Troubleshooting\n\n</summary>\n<details>\n<summary>\n\n### 🚫 Redownload not available\n\n</summary>\n\nIf the following error occurs, you probably [haven't yet gotten or purchased the\napp from the App Store](#mas-install).\n\n> This redownload is not available for this Apple Account either because it was\n> bought by a different user or the item was refunded or canceled.\n\n</details>\n<details>\n<summary>\n\n### ❓ Other issues\n\n</summary>\n\nIf mas doesn't work as expected (e.g., apps can't be installed/updated), run\n`mas reset`, then try again.\n\nIf the issue persists, please [file a bug](\n  https://github.com/mas-cli/mas/issues/new?template=01-bug-report.yaml\n).\n\nAll feedback is much appreciated!\n\n</details>\n</details>\n<details>\n<summary>\n\n## 🏗 Building\n\n</summary>\n\nmas can be built in Xcode or built by the following script:\n\n```shell\nScripts/build\n```\n\nBuild output can be found in the `.build` folder in the project's root folder.\n\n</details>\n<details>\n<summary>\n\n## 🧪 Testing\n\n</summary>\n\nTests are implemented in\n[Swift Testing](https://developer.apple.com/xcode/swift-testing).\n\nTests can be run by the following script:\n\n```shell\nScripts/test\n```\n\n</details>\n<details>\n<summary>\n\n## 📄 License\n\n</summary>\n\nCode is under the [MIT license](LICENSE).\n\nmas was originally created by Andrew Naylor\n([@argon on GitHub](https://github.com/argon) /\n[@argon on X](https://x.com/argon)).\n\n</details>\n"
  },
  {
    "path": "Scripts/_setup_script",
    "content": "#!/bin/zsh -Ndefgku\n#\n# Scripts/_setup_script\n# mas\n#\n# Copyright © 2025 mas-cli. All rights reserved.\n#\n# Performs boilerplate setup for scripts.\n#\n\nbuiltin unalias -as\nsetopt\\\n autopushd\\\n combiningchars\\\n extendedglob\\\n extendedhistory\\\n no_globalrcs\\\n histexpiredupsfirst\\\n histignorespace\\\n histverify\\\n incappendhistorytime\\\n interactivecomments\\\n pipefail\\\n no_rcs\\\n no_unset\nexport -r HISTCHARS='!^#'\nexport -r IFS=$' \\t\\n\\0'\nexport -r NULLCMD=cat\nexport -r PAGER=cat\nexport -r READNULLCMD=cat\nexport -r TMPDIR=\"${\"${TMPDIR:-/tmp/}\"/%(#b)([^\\/])/\"${match[1]}\"/}\"\nexport -r TMPPREFIX=\"${TMPPREFIX:-\"${TMPDIR}\"zsh}\"\nunset CDPATH\nunset ENV\nunset KEYBOARD_HACK\nunset TMPSUFFIX\nunset WORDCHARS\n\nreadonly mas_folder=\"${0:A:h:h}\"\nif ! cd -- \"${mas_folder}\"; then\n\tprintf $'Error: Failed to cd into mas folder: %s\\n' \"${mas_folder}\" >&2\n\texit 1\nfi\n\nprint_notice() {\n\t[[ -v MAS_DO_NOT_PRINT_NOTICE ]] && return\n\tif [[ -t 1 ]]; then\n\t\tlocal -r prefix=$'\\e[1;34m==>\\e[0m'\n\telse\n\t\tlocal -r prefix='==>'\n\tfi\n\tprintf $'%s %s mas %s%s\\n' \"${prefix}\" \"${1}\" \"${MAS_VERSION:-$(Scripts/version)}\" \"${${*:2}:+ (arguments: ${${(q)@:2}[*]})}\"\n}\n\nensure_command_available() {\n\tlocal -i return_status=0\n\tlocal command\n\tfor command in \"${@}\"; do\n\t\tif ! whence \"${command}\" >/dev/null; then\n\t\t\tprintf $'error: %s is not installed. Run \\'Scripts/bootstrap\\' or \\'brew install %s\\'.\\n' \"${command}\" \"${command}\" >&2\n\t\t\treturn_status=1\n\t\tfi\n\tdone\n\treturn \"${return_status}\"\n}\n"
  },
  {
    "path": "Scripts/bootstrap",
    "content": "#!/bin/zsh -Ndefgku\n#\n# Scripts/bootstrap\n# mas\n#\n# Copyright © 2025 mas-cli. All rights reserved.\n#\n# Installs dependencies for Scripts/format & Scripts/lint.\n#\n# Usage: bootstrap [<brew-bundle-install-argument>...]\n#\n\n. \"${0:A:h}/_setup_script\"\n\nprint_notice '👢 Bootstrapping' \"${@}\"\n\nif ! whence brew >/dev/null; then\n\t/bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"\nfi\n\nbrew update -q\ninstalled_formulae=(\"${(f)$(brew list --formulae)}\")\nreadonly -a installed_formulae\nbootstrap_formulae=(\"${(f)$(brew deps --union \"${(f)$(brew bundle list --formulae)}\")}\")\nreadonly -a bootstrap_formulae\n# shellcheck disable=SC2086\n((\"${#installed_formulae:*bootstrap_formulae}\")) && brew upgrade --overwrite -q ${installed_formulae:*bootstrap_formulae}\nbrew bundle upgrade -fq \"${@}\"\nbrew upgrade --overwrite -q \"${bootstrap_formulae[@]}\"\n"
  },
  {
    "path": "Scripts/build",
    "content": "#!/bin/zsh -Ndefgku\n#\n# Scripts/build\n# mas\n#\n# Copyright © 2025 mas-cli. All rights reserved.\n#\n# Builds the Swift package.\n#\n\n. \"${0:A:h}/_setup_script\"\n\nprint_notice '🏗​ Building' \"${@}\"\n\nexport -r MAS_DISTRIBUTION=\"${1:-}\"\n\nswift build \"${@:2}\"\n"
  },
  {
    "path": "Scripts/clean",
    "content": "#!/bin/zsh -Ndefgku\n#\n# Scripts/clean\n# mas\n#\n# Copyright © 2025 mas-cli. All rights reserved.\n#\n# Deletes the build folder & other generated files.\n#\n\n. \"${0:A:h}/_setup_script\"\n\nprint_notice '🗑​ Cleaning' \"${@}\"\n\nzmodload zsh/zutil\nzparseopts -D -A received_flag D P r x\n\nif ! [[ -v 'received_flag[-P]' ]]; then\n\tswift package \"${${received_flag[-D]+clean}:-reset}\"\nfi\nif [[ -v 'received_flag[-r]' && -e Package.resolved ]]; then\n\ttrash Package.resolved\nfi\nif [[ -v 'received_flag[-x]' && -d .swiftpm ]]; then\n\ttrash .swiftpm\nfi\n"
  },
  {
    "path": "Scripts/format",
    "content": "#!/bin/zsh -Ndefgku\n#\n# Scripts/format\n# mas\n#\n# Copyright © 2025 mas-cli. All rights reserved.\n#\n# Automatically formats & fixes style violations using various tools.\n#\n# Please keep in sync with Scripts/lint.\n#\n\n. \"${0:A:h}/_setup_script\"\n\nprint_notice '🧹 Formatting' \"${@}\"\n\nensure_command_available markdownlint-cli2 swiftformat swiftlint\n\nexport -r MAS_DISTRIBUTION=format\n\nprintf -- $'--> 🕊​ SwiftFormat\\n'\nscript -q /dev/null swiftformat --strict --markdown-files format-strict . |\n (grep -vxE '(?:\\^D\\x08{2})?Running SwiftFormat\\.{3}\\r|Reading (?:config|swift-version) file at .*|\\x1b\\[32mSwiftFormat completed in \\d+(?:\\.\\d+)?s\\.\\x1b\\[0m\\r|0/\\d+ files formatted\\.\\r' || true)\n\nprintf -- $'--> 🦅 SwiftLint\\n'\nswiftlint --fix --quiet --reporter relative-path\n\nprintf -- $'--> 〽️ Markdown\\n'\n# shellcheck disable=SC1036\nmarkdownlint-cli2 --fix -- ***/*.md(.)\n\nprintf -- $'--> 🚷 Non-Executables\\n'\nreadonly -a non_executables=(Scripts/***/*(N.^f+111))\nif ((\"${#non_executables[@]}\")); then\n\tchmod -vv a+x \"${non_executables[@]}\"\n\texit 1\nfi\n"
  },
  {
    "path": "Scripts/generate_manual",
    "content": "#!/bin/zsh -Ndefgku\n#\n# Scripts/generate_manual\n# mas\n#\n# Copyright © 2025 mas-cli. All rights reserved.\n#\n# Generates man page.\n#\n\n. \"${0:A:h}/_setup_script\"\n\nprint_notice '📖 Generating man pages for' \"${@}\"\n\nexport -r MAS_DISTRIBUTION=\"${1:-}\"\n\nswift package generate-manual \"${@:2}\"\n"
  },
  {
    "path": "Scripts/generate_token",
    "content": "#!/bin/zsh -Ndefgku\n#\n# Scripts/generate_token\n# mas\n#\n# Copyright © 2025 mas-cli. All rights reserved.\n#\n# Generates a GitHub App installation access token for GitHub Workflows.\n#\n\n. \"${0:A:h}/_setup_script\"\n\nreadonly header=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9\nreadonly payload=\"${${$(printf '{\"iss\":%s,\"iat\":%s,\"exp\":%s}' \"${TOKEN_APP_ID}\" \"$((\"$(date +%s)\" - 60))\"\\\n \"$((\"$(date +%s)\" + 540))\" | base64)//[=$'\\n']}//\\/+/_-}\"\n\n\n# shellcheck disable=SC1036,SC1072,SC1073\ncurl\\\n -sX POST\\\n -H \"Authorization: Bearer ${header}.${payload}.${${$(printf %s \"${header}.${payload}\" |\n openssl dgst -sha256 -sign =(printf %s \"${TOKEN_APP_PRIVATE_KEY}\") | base64)//[=$'\\n']}//\\/+/_-}\"\\\n -H 'Accept: application/vnd.github+json'\\\n \"https://api.github.com/app/installations/${TOKEN_APP_INSTALLATION_ID}/access_tokens\" |\n jq -r .token\n"
  },
  {
    "path": "Scripts/lint",
    "content": "#!/bin/zsh -Ndfgku\n#\n# Scripts/lint\n# mas\n#\n# Copyright © 2025 mas-cli. All rights reserved.\n#\n# Reports style violations without making any modifications to the code.\n#\n# Please keep in sync with Scripts/format.\n#\n\n# shellcheck disable=SC1036,SC1056,SC1072\n. \"${0:A:h}/_setup_script\"\n\nprint_notice '🚨 Linting' \"${@}\"\n\nensure_command_available actionlint git markdownlint-cli2 shellcheck swiftformat swiftlint yamllint || exit\n[[ \"$(/usr/bin/arch)\" = arm64 && \"${$(sw_vers -productVersion)%%.*}\" -ge 15 ]]\ninteger -r can_use_periphery=\"$((! ?))\"\n# shellcheck disable=SC1073,SC1083\n((can_use_periphery)) && { ensure_command_available periphery || exit }\n\nzmodload zsh/zutil\nzparseopts -D -A received_flag P\n\nexport -r MAS_DISTRIBUTION=lint\n\ninteger exit_status=0\n\nprintf -- $'--> 🕊​ SwiftFormat\\n'\nscript -q /dev/null swiftformat --lint --markdown-files format-strict . |\n (grep -vxE '(?:\\^D\\x08{2})?Running SwiftFormat\\.{3}\\r|\\(lint mode - no files will be changed\\.\\)\\r|Reading (?:config|swift-version) file at .*|\\x1b\\[32mSwiftFormat completed in \\d+(?:\\.\\d+)?s\\.\\x1b\\[0m\\r|0/\\d+ files require formatting\\.\\r|Source input did not pass lint check\\.\\r' || true)\n((exit_status |= ${?}))\n\nprintf -- $'--> 🦅 SwiftLint\\n'\nswiftlint --strict --quiet --reporter relative-path\n((exit_status |= ${?}))\n\nif ((can_use_periphery)) && ! [[ -v 'received_flag[-P]' ]]; then\n\tprintf -- $'--> 🌀 Periphery\\n'\n\tperiphery scan --exclude-tests |\n\t (grep -vxE '(?:\\x1b\\[0;1;32m|\\^D\\x08{2})\\* (?:\\x1b\\[0;0m\\x1b\\[0;1m)?No unused code detected\\.(?:\\x1b\\[0;0m)?\\r?' || true)\n\t((exit_status |= ${?}))\n\n\tprintf -- $'--> 🌀 Periphery Tests\\n'\n\tperiphery scan |\n\t (grep -vxE '(?:\\x1b\\[0;1;32m|\\^D\\x08{2})\\* (?:\\x1b\\[0;0m\\x1b\\[0;1m)?No unused code detected\\.(?:\\x1b\\[0;0m)?\\r?' || true)\n\t((exit_status |= ${?}))\nfi\n\nprintf -- $'--> 〽️ Markdown\\n'\nmarkdownlint-cli2 -- ***/*.md(.)\n((exit_status |= ${?}))\n\nprintf -- $'--> 📝 YAML\\n'\nyamllint -s .\n((exit_status |= ${?}))\n\nprintf -- $'--> 🌳 Git\\n'\ngit diff --check\n((exit_status |= ${?}))\n\nprintf -- $'--> 💤 Zsh\\n'\nfor script in Scripts/***/*(.); do\n\t/bin/zsh -n \"${script}\"\n\t((exit_status |= ${?}))\ndone\n\nprintf -- $'--> 🐙 ActionLint\\n'\nactionlint -shellcheck shellcheck\n((exit_status |= ${?}))\n\nprintf -- $'--> 🐚 ShellCheck\\n'\nshellcheck -s bash -o all -e SC1009,SC1088,SC2296,SC2298,SC2299,SC2300,SC2301,SC2312 -a -P SCRIPTDIR Scripts/***/*(.)\n((exit_status |= ${?}))\n\nprintf -- $'--> 🚷 Non-Executables\\n'\nreadonly -a non_executables=(Scripts/***/*(N.^f+111))\nif ((\"${#non_executables[@]}\")); then\n\tprintf $'%s\\n' \"${non_executables[@]}\"\n\t((exit_status |= 1))\nfi\n\nexit \"${exit_status}\"\n"
  },
  {
    "path": "Scripts/package",
    "content": "#!/bin/zsh -Ndefgku\n#\n# Scripts/package\n# mas\n#\n# Copyright © 2025 mas-cli. All rights reserved.\n#\n# Builds .pkg installer.\n#\n\n. \"${0:A:h}/_setup_script\"\n\nprint_notice '📦 Packaging installer for' \"${@}\"\n\nexport MAS_DO_NOT_PRINT_NOTICE=\nScripts/build \"${1:-}\" -c release \"${@:2}\"\nunset MAS_DO_NOT_PRINT_NOTICE\n\nreadonly build_folder=.build\nreadonly destination_folder=\"${build_folder}/destination\"\nreadonly installation_folder=/usr/local/opt/mas\nreadonly installation_staging_folder=\"${destination_folder}${installation_folder}\"\nreadonly usr_local_bin_staging_folder=\"${destination_folder}/usr/local/bin\"\nversion=\"$(Scripts/version)\"\nreadonly version\n\nswift package generate-manual\n\nmkdir -p \"${installation_staging_folder}/bin\"\nmkdir -p \"${installation_staging_folder}/etc/bash_completion.d\"\nmkdir -p \"${installation_staging_folder}/share/fish/vendor_completions.d\"\nmkdir -p \"${installation_staging_folder}/share/man/man1\"\nmkdir -p \"${usr_local_bin_staging_folder}\"\n\ncp LICENSE README.md \"${installation_staging_folder}\"\ncp contrib/completion/mas-completion.bash \"${installation_staging_folder}/etc/bash_completion.d/mas\"\ncp contrib/completion/mas.fish \"${installation_staging_folder}/share/fish/vendor_completions.d/mas.fish\"\nln -f \"$(swift build -c release --show-bin-path \"${@:2}\")/mas\" \"${installation_staging_folder}/bin/mas\"\nln -f .build/plugins/GenerateManual/outputs/mas/mas.1 \"${installation_staging_folder}/share/man/man1/mas.1\"\n\nln -fs \"${installation_folder}/bin/mas\" \"${usr_local_bin_staging_folder}/mas\"\n\narchs=(\"${(s: :n)$(lipo -archs \"${installation_staging_folder}/bin/mas\")}\")\n# shellcheck disable=SC2034\nreadonly -a archs\n\npkgbuild\\\n --identifier io.github.mas-cli.mas\\\n --install-location /\\\n --version \"${version}\"\\\n --root \"${destination_folder}\"\\\n \"${build_folder}/mas.pkg\"\n\n# shellcheck disable=SC1036\nproductbuild\\\n --distribution =(<<<\\\n'<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<installer-gui-script minSpecVersion=\"2\">\n\t<title>mas</title>\n\t<options customize=\"never\" require-scripts=\"false\" hostArchitectures=\"'\"${(j:,:)archs[@]}\"'\"/>\n\t<volume-check>\n\t\t<allowed-os-versions>\n\t\t\t<os-version min=\"13\"/>\n\t\t</allowed-os-versions>\n\t</volume-check>\n\t<choices-outline>\n\t\t<line choice=\"mas\"/>\n\t</choices-outline>\n\t<choice id=\"mas\" title=\"mas\" visible=\"false\">\n\t\t<pkg-ref id=\"mas\">mas.pkg</pkg-ref>\n\t</choice>\n</installer-gui-script>'\n )\\\n --package-path \"${build_folder}\"\\\n \"${build_folder}/mas-${version//\\//_}-${(j:-:)archs[@]}.pkg\"\n"
  },
  {
    "path": "Scripts/prebuild",
    "content": "#!/bin/zsh -Ndefgku\n#\n# Scripts/prebuild\n# mas\n#\n# Copyright © 2025 mas-cli. All rights reserved.\n#\n# Prebuilds the Swift package.\n#\n\n. \"${0:A:h}/_setup_script\"\n\nprint_notice '🎬 Prebuilding' \"${@}\"\n\n# Generate Swift file containing build information.\n# shellcheck disable=SC1102\nprintf '//\n// MAS+BuildInformation.swift\n// mas\n//\n// Copyright © %s mas-cli. All rights reserved.\n//\n\nextension MAS {\n\tstatic let version = \"%s\"\n\tstatic let distribution = \"%s\"\n\tstatic let gitOrigin = \"%s\"\n\tstatic let gitRevision = \"%s\"\n\tstatic let swiftVersion = \"%s\"\n\tstatic let swiftDriverVersion = \"%s\"\n}\n'\\\n \"$(date +%Y)\"\\\n \"$(Scripts/version)\"\\\n \"${MAS_DISTRIBUTION:-unknown}\"\\\n \"$(git remote get-url origin)\"\\\n \"$(git rev-parse HEAD)\"\\\n \"${${${$(swift --version 2>/dev/null)##( |[[:alpha:]])##}%%$'\\n'*}:-unknown}\"\\\n \"${${(SM)$(swift --version 2>&1 >/dev/null)##[[:digit:]]([[:digit:]]|.)##}:-unknown}\"\\\n >\"${1}/MAS+BuildInformation.swift\"\n"
  },
  {
    "path": "Scripts/release_cancel",
    "content": "#!/bin/zsh -Ndefgku\n#\n# Scripts/release_cancel\n# mas\n#\n# Copyright © 2025 mas-cli. All rights reserved.\n#\n# Cancels a GitHub draft release.\n#\n# Usage: release_cancel <draft-release-tag>\n#\n\n. \"${0:A:h}/_setup_script\"\n\nreadonly tag=\"${1}\"\n\nexport MAS_VERSION=\"${tag#v}\"\nprint_notice '❌ Canceling release for' \"${@}\"\nunset MAS_VERSION\n\nbump_url=\"$(gh release -R https://github.com/mas-cli/mas download \"${tag}\" -p bump.url -O - 2>/dev/null || true)\"\nreadonly bump_url\nif [[ -n \"${bump_url}\" ]]; then\n\tprintf $'\\n'\n\tgh pr close \"${bump_url}\" -d\n\tprintf $'\\n'\nelse\n\tprintf $'\\nNo tap formula bump PR URL found for draft release tag %s\\n\\n' \"${tag}\"\nfi\n\ngh release -R https://github.com/mas-cli/mas delete \"${tag}\" --cleanup-tag -y\n"
  },
  {
    "path": "Scripts/release_start",
    "content": "#!/bin/zsh -Ndefgku\n#\n# Scripts/release_start\n# mas\n#\n# Copyright © 2025 mas-cli. All rights reserved.\n#\n# Starts the release process by creating & pushing a signed annotated version tag to the GitHub mas-cli/mas repo.\n#\n# Usage: release_start <version-tag-name> <version-title> [<version-ref>]\n#\n# <version-tag-name> must match the following zsh pattern:\n#\n# ^v[[:digit:]]+(\\.[[:digit:]]+)*(-(alpha|beta|rc)\\.[[:digit:]]+)?$\n#\n# <version-title> must may contain at most 64 characters, which may be only visible characters or spaces\n#\n# <version-ref> if optional value supplied, must be on the main branch; defaults to HEAD\n#\n\n. \"${0:A:h}/_setup_script\"\n\nreadonly tag=\"${1}\"\nreadonly title=\"${2}\"\nreadonly ref=\"${3:-HEAD}\"\n\nexport MAS_VERSION=\"${tag#v}\"\nprint_notice '🚀 Starting release for' \"${@}\"\nunset MAS_VERSION\nprintf $'\\n'\n\nif [[ ! \"${tag}\" =~ '^v[[:digit:]]+(\\.[[:digit:]]+)*(-(alpha|beta|rc)\\.[[:digit:]]+)?$' ]]; then\n\tprintf $'%s is not a valid version tag\\n' \"${tag}\" >&2\n\texit 1\nfi\n\nif ((\"${#title}\" > 64)); then\n\tprintf $'\\'%s\\' is too long for a version title, which may contain at most 64 characters\\n' \"${(q)title}\" >&2\n\texit 2\nfi\n\nif [[ \"${title}\" =~ [[:cntrl:]$'\\t\\n\\r'] ]]; then\n\tprintf $'\\'%s\\' is not a valid version title, which may contain only visible characters or spaces\\n' \"${(q)title}\" >&2\n\texit 3\nfi\n\n# shellcheck disable=SC1027,SC1036,SC1072,SC1073\nif [[ \"${title}\" = (' '*|*' ') ]]; then\n\tprintf $'\\'%s\\' is not a valid version title, which may not begin or end with a space\\n' \"${(q)title}\" >&2\n\texit 4\nfi\n\nif ! git merge-base --is-ancestor \"${ref}\" upstream/main; then\n\tprintf $'%s is not a valid reference for a version, which must be on the upstream/main branch\\n' \"${ref}\" >&2\n\texit 5\nfi\n\ngit tag -s \"${tag}\" -m \"${title}\" \"${ref}\"\n\nprintf $'Created version tag %s with title \\'%s\\' for reference %s\\n\\n' \"${tag}\" \"${(q)title}\" \"${ref}\"\n\ngit push upstream tag \"${tag}\"\n"
  },
  {
    "path": "Scripts/setup_workflow_repo",
    "content": "#!/bin/zsh -Ndefgku\n#\n# Scripts/setup_workflow_repo\n# mas\n#\n# Copyright © 2025 mas-cli. All rights reserved.\n#\n# Sets up the repo for use in a GitHub workflow.\n#\n\n. \"${0:A:h}/_setup_script\"\n\n# shellcheck disable=SC2066\nfor branch in \"${(f)\"$(git for-each-ref refs/remotes/origin --format='%(if)%(symref)%(then)%(else)%(refname:strip=-1)%(end)')\":#}\"; do\n\tgit branch --track \"${branch}\" \"origin/${branch}\" >/dev/null 2>&1 || true\ndone\n"
  },
  {
    "path": "Scripts/test",
    "content": "#!/bin/zsh -Ndefgku\n#\n# Scripts/test\n# mas\n#\n# Copyright © 2025 mas-cli. All rights reserved.\n#\n# Runs mas tests.\n#\n\n. \"${0:A:h}/_setup_script\"\n\nprint_notice '🧪 Testing' \"${@}\"\n\nexport -r MAS_DISTRIBUTION=test\n\nswift test --disable-xctest -q \"${@}\"\n"
  },
  {
    "path": "Scripts/update_dependencies",
    "content": "#!/bin/zsh -GNdefgku\n#\n# Scripts/update_dependencies\n# mas\n#\n# Copyright © 2025 mas-cli. All rights reserved.\n#\n# Update dependencies.\n#\n\n. \"${0:A:h}/_setup_script\"\n\nprint_notice '⬆️​ Updating dependencies for' \"${@}\"\n\nprintf -- $'--> 🍺 Homebrew\\n'\nexport MAS_DO_NOT_PRINT_NOTICE=\nScripts/bootstrap\nunset MAS_DO_NOT_PRINT_NOTICE\n\nprintf -- $'--> 🕊​ Swift\\n'\nswift package update\n"
  },
  {
    "path": "Scripts/update_headers",
    "content": "#!/bin/zsh -GNdefgku\n#\n# Scripts/update_headers\n# mas\n#\n# Copyright © 2025 mas-cli. All rights reserved.\n#\n# Generates headers for Apple private frameworks.\n#\n\n. \"${0:A:h}/_setup_script\"\n\nensure_command_available ipsw\n\nzmodload zsh/zutil\nzparseopts -D -A received_flag C X\n\nreadonly -a frameworks_globs=(\"${@:-*(/)}\")\n\ncd Sources/PrivateFrameworks/include\n\nfor framework in ${~frameworks_globs[@]}; do\n\t! [[ -v 'received_flag[-X]' ]] && ipsw class-dump --headers --output . /System/Volumes/Preboot/Cryptexes/OS/System/Library/dyld/dyld_shared_cache_arm64e -- \"${framework}\"\n\n\t# shellcheck disable=SC1046,SC1047,SC1072,SC1073\n\tif ! [[ -v 'received_flag[-C]' ]]; then\n\t\tcd -- \"${framework}\"\n\n\t\t# shellcheck disable=SC1036\n\t\tsed -Ei ''\\\n\t\t -e 's!^//    -!// -!g'\\\n\t\t -e 's!^//  !//!g'\\\n\t\t -e '/^#(define|endif|ifndef).*/d'\\\n\t\t -e '/^ *\\/\\*.*\\*\\/$/d'\\\n\t\t -e '/^@import Foundation;$/d'\\\n\t\t -e 's/^    /\\t/g'\\\n\t\t -e 's/_Bool/BOOL/g'\\\n\t\t -e 's/^- \\(id\\)description;$/- \\(nonnull NSString \\*\\)description;/g'\\\n\t\t -e 's/^- \\(void\\)encodeWithCoder:\\(id\\)coder;$/- \\(void\\)encodeWithCoder:\\(nullable NSCoder \\*\\)coder;/g'\\\n\t\t -e 's/^- \\(id\\)initWithCoder:\\(id\\)coder;$/- \\(nonnull instancetype\\)initWithCoder:\\(nullable NSCoder \\*\\)coder;/g'\\\n\t\t -e 's/^- \\(BOOL\\)isEqual:\\(id\\)equal;$/- \\(BOOL\\)isEqual:\\(nullable id\\)object;/g'\\\n\t\t -e 's/^\\+ \\(id\\)interface;$/\\+ \\(nonnull NSXPCInterface \\*\\)interface;/g'\\\n\t\t -e 's/\\(copy\\)/\\(copy, nullable\\)/g'\\\n\t\t -e 's/\\(copy, nonatomic\\)/\\(copy, nonatomic, nullable\\)/g'\\\n\t\t -e 's/\\(id\\)client/\\(nullable ISStoreClient \\*\\)client/g'\\\n\t\t -e 's/\\(id\\)dictionary/\\(nullable NSDictionary \\*\\)dictionary/g'\\\n\t\t -e 's/\\(id\\)init/\\(nonnull instancetype)init/g'\\\n\t\t -e 's/\\(retain\\)/\\(retain, nullable\\)/g'\\\n\t\t -e 's/\\(retain, nonatomic\\)/\\(retain, nonatomic, nullable\\)/g'\\\n\t\t -e 's/\\(id\\)dsid/\\(nullable NSNumber \\*\\)dsID/g'\\\n\t\t -e 's/NSArray \\*downloads/NSArray\\<SSDownload \\*\\> \\*downloads/g'\\\n\t\t -e 's/\\(id\\)productID/\\(nonnull NSNumber \\*\\)productID/g'\\\n\t\t -e 's/- \\(id\\)copyWithZone:\\(struct _NSZone \\*\\)zone;/- \\(nonnull instancetype\\)copyWithZone:\\(nullable struct _NSZone \\*\\)zone;/g'\\\n\t\t -e 's/\\(id\\)progress/\\(nullable SSOperationProgress \\*\\)progress/g'\\\n\t\t -e 's/\\(id\\)url/\\(nullable NSURL \\*\\)url/g'\\\n\t\t -e 's/:\\(id\\)error/:\\(nullable NSError \\*\\)error/g'\\\n\t\t -e 's/NSObject\\<OS_dispatch_queue\\> \\*/dispatch_queue_t /g'\\\n\t\t -e 's/NSObject\\<OS_dispatch_source\\> \\*/dispatch_source_t /g'\\\n\t\t -e 's!id /\\* block \\*/!UnknownBlock!g'\\\n\t\t ***/*.h(.N)\n\n\t\tfor header in ***/*.h(.N); do\n\t\t\tsed -i '' -e ':a' -e '/^\\n*$/{$d;N;ba' -e '}' \"${header}\"\n\t\tdone\n\n\t\tcd ..\n\tfi\ndone\n"
  },
  {
    "path": "Scripts/version",
    "content": "#!/bin/zsh -Ndefgku\n#\n# Scripts/version\n# mas\n#\n# Copyright © 2025 mas-cli. All rights reserved.\n#\n# Outputs the mas version.\n#\n\n. \"${0:A:h}/_setup_script\"\n\nbranch=\"${\"$(git rev-parse --abbrev-ref HEAD)\":/main}\"\nif [[ \"${branch}\" = HEAD ]]; then\n\tif ! git show-ref --verify --quiet refs/heads/main || git merge-base --is-ancestor HEAD main; then\n\t\treadonly branch=\n\telse\n\t\treadonly branch=\"${\"${\"${(fnO)\"$(git branch --contains HEAD --format '%(ahead-behind:HEAD) %(refname:short)')\"}\"[1]}\"##* }\"\n\tfi\nelse\n\treadonly branch\nfi\n\nprintf $'%s%s%s\\n'\\\n \"${\"$(git describe --tags 2>/dev/null)\"#v}\"\\\n \"${branch:+\"-${branch}\"}\"\\\n \"${\"$(git diff-index HEAD --;git ls-files --exclude-standard --others)\":+\"${MAS_DIRTY_INDICATOR-+}\"}\"\n"
  },
  {
    "path": "Sources/PrivateFrameworks/PrivateFrameworks.c",
    "content": "// Xcode will not build without this file causing an object file to be compiled.\n"
  },
  {
    "path": "Sources/PrivateFrameworks/include/CommerceKit/CKDownloadDirectory.h",
    "content": "//\n// CKDownloadDirectory.h\n// mas\n//\n// Copyright © 2018 mas-cli. All rights reserved.\n//\n\nNSString * _Nonnull CKDownloadDirectory(NSString * _Nullable target);\n"
  },
  {
    "path": "Sources/PrivateFrameworks/include/CommerceKit/CKDownloadQueue.h",
    "content": "//\n// Generated by https://github.com/blacktop/ipsw (Version: 3.1.660, BuildCommit: Homebrew)\n//\n// - LC_BUILD_VERSION:  Platform: macOS, MinOS: 26.2, SDK: 26.2, Tool: ld (1230.3)\n// - LC_SOURCE_VERSION: 716.2.2.0.0\n//\n\n@interface CKDownloadQueue : CKServiceInterface {\n\tNSMutableDictionary *_downloadsByItemID;\n\tNSLock *_downloadsLock;\n\tid _observerToken;\n\tNSLock *_tokenLock;\n}\n\n+ (nonnull instancetype)sharedDownloadQueue;\n\n@property (retain, nonatomic, nullable) NSMutableDictionary<NSString *, CKDownloadQueueClient *> *downloadQueueObservers; // <NSString * _Nonnull, CKDownloadQueueClient * _Nonnull>\n@property (readonly, nonatomic, nullable) NSArray<SSDownload *> *downloads; // Unverified generic type\n@property (retain, nonatomic, nullable) CKDownloadQueueClient *sharedObserver;\n\n- (void)addDownload:(nonnull SSDownload *)download;\n- (nonnull NSString *)addObserver:(nullable id <CKDownloadQueueObserver>)observer;\n- (nonnull NSString *)addObserver:(nullable id <CKDownloadQueueObserver>)observer forDownloadTypes:(long long)downloadTypes;\n- (nonnull NSString *)addObserverForDownloadTypes:(long long)downloadTypes withBlock:(nullable UnknownBlock)block;\n- (BOOL)cacheReceiptDataForDownload:(nullable SSDownload *)download;\n- (void)cancelDownload:(nullable SSDownload *)download promptToConfirm:(BOOL)promptToConfirm askToDelete:(BOOL)askToDelete;\n- (void)checkStoreDownloadQueueForAccount:(nullable ISStoreAccount *)account; // Unverified account type\n- (void)connectionWasInterrupted;\n- (nullable SSDownload *)downloadForItemIdentifier:(unsigned long long)identifier; // Unverified return type\n- (void)fetchIconForItemIdentifier:(unsigned long long)identifier atURL:(nullable NSURL *)url replyBlock:(nonnull UnknownBlock)block;\n- (nonnull instancetype)initWithStoreClient:(nullable ISStoreClient *)client; // Unverified client type\n- (void)lockApplicationsForBundleID:(nullable NSString *)bundleID; // Unverified bundleID type\n- (void)lockedApplicationTriedToLaunchAtPath:(nullable NSString *)path; // Unverified path type\n- (void)pauseDownloadWithItemIdentifier:(unsigned long long)identifier;\n- (void)performedIconAnimationForDownloadWithIdentifier:(unsigned long long)identifier;\n- (void)removeDownloadWithItemIdentifier:(unsigned long long)identifier;\n- (void)removeObserver:(nullable NSString *)observerUUID; // Unverified observerUUID type\n- (void)resumeDownloadWithItemIdentifier:(unsigned long long)identifier;\n- (void)unlockApplicationsWithBundleIdentifier:(nullable NSString *)bundleID; // Unverified bundleID type\n\n@end\n"
  },
  {
    "path": "Sources/PrivateFrameworks/include/CommerceKit/CKDownloadQueueObserver-Protocol.h",
    "content": "//\n// CKDownloadQueueObserver-Protocol.h\n// mas\n//\n// Copyright © 2018 mas-cli. All rights reserved.\n//\n\n@protocol CKDownloadQueueObserver\n\n@required\n\n- (void)downloadQueue:(nonnull CKDownloadQueue *)queue changedWithAddition:(nonnull SSDownload *)download;\n- (void)downloadQueue:(nonnull CKDownloadQueue *)queue changedWithRemoval:(nonnull SSDownload *)download;\n- (void)downloadQueue:(nonnull CKDownloadQueue *)queue statusChangedForDownload:(nonnull SSDownload *)download;\n\n@optional\n\n@end\n"
  },
  {
    "path": "Sources/PrivateFrameworks/include/CommerceKit/CKPurchaseController.h",
    "content": "//\n// Generated by https://github.com/blacktop/ipsw (Version: 3.1.660, BuildCommit: Homebrew)\n//\n// - LC_BUILD_VERSION:  Platform: macOS, MinOS: 26.2, SDK: 26.2, Tool: ld (1230.3)\n// - LC_SOURCE_VERSION: 716.2.2.0.0\n//\n\ntypedef void (^SSPurchaseCompletion)(SSPurchase * _Nonnull purchase, BOOL completed, NSError * _Nullable error, SSPurchaseResponse * _Nullable response);\n\n@interface CKPurchaseController : CKServiceInterface {\n\tNSArray *_adoptionEligibleItems;\n\tNSNumber *_adoptionErrorNumber;\n\tNSNumber *_adoptionServerStatus;\n\tNSMutableArray *_purchases;\n\tNSMutableArray *_rejectedPurchases;\n}\n\n+ (void)setNeedsSilentMachineAuthorization:(BOOL)needsSilentMachineAuthorization;\n+ (nonnull instancetype)sharedPurchaseController;\n\n@property (copy, nullable) void (^dialogHandler)(CKDialog * _Nullable); // Unverified type\n\n- (void)_performVPPReceiptRenewal;\n- (BOOL)adoptionCompletedForBundleID:(nullable NSString *)bundleID;\n- (void)cancelPurchaseWithProductID:(nullable NSNumber *)productID;\n- (void)checkServerDownloadQueue;\n- (void)performPurchase:(nonnull SSPurchase *)purchase withOptions:(unsigned long long)options completionHandler:(nullable SSPurchaseCompletion)handler;\n- (nullable SSPurchase *)purchaseInProgressForProductID:(nullable NSNumber *)productID; // Unverified return type\n- (nullable NSArray<SSPurchase *> *)purchasesInProgress; // Unverified return type\n- (void)resumeDownloadForPurchasedProductID:(nullable NSNumber *)productID; // Unverified productID type\n- (void)startPurchases:(nullable NSArray<SSPurchase *> *)purchases shouldStartDownloads:(BOOL)shouldStartDownloads eventHandler:(nullable void (^)(NSArray<SSPurchase *> * _Nonnull))handler; // Unverified purchases generic type / handler type\n- (void)startPurchases:(nullable NSArray<SSPurchase *> *)purchases withOptions:(unsigned long long)options completionHandler:(nullable void (^)(NSArray<SSPurchase *> * _Nonnull))handler; // Unverified purchases type / handler parameter type\n\n@end\n"
  },
  {
    "path": "Sources/PrivateFrameworks/include/CommerceKit/CKServiceInterface.h",
    "content": "//\n// Generated by https://github.com/blacktop/ipsw (Version: 3.1.660, BuildCommit: Homebrew)\n//\n// - LC_BUILD_VERSION:  Platform: macOS, MinOS: 26.2, SDK: 26.2, Tool: ld (1230.3)\n// - LC_SOURCE_VERSION: 716.2.2.0.0\n//\n\n@interface CKServiceInterface : ISServiceProxy\n\n@end\n"
  },
  {
    "path": "Sources/PrivateFrameworks/include/CommerceKit/CommerceKit.h",
    "content": "//\n// Generated by https://github.com/blacktop/ipsw (Version: 3.1.660, BuildCommit: Homebrew)\n//\n// - LC_BUILD_VERSION:  Platform: macOS, MinOS: 26.2, SDK: 26.2, Tool: ld (1230.3)\n// - LC_SOURCE_VERSION: 716.2.2.0.0\n//\n\n@import StoreFoundation;\n\n@class CKDialog, CKDownloadQueueClient;\n\n@protocol CKDownloadQueueObserver;\n\n#import \"CKServiceInterface.h\"\n#import \"CKDownloadDirectory.h\"\n#import \"CKDownloadQueue.h\"\n#import \"CKDownloadQueueObserver-Protocol.h\"\n#import \"CKPurchaseController.h\"\n"
  },
  {
    "path": "Sources/PrivateFrameworks/include/CommerceKit/module.modulemap",
    "content": "module CommerceKit [system] [no_undeclared_includes] {\n\trequires macos, objc\n\tuse StoreFoundation\n\tlink framework \"CommerceKit\"\n\tumbrella header \"CommerceKit.h\"\n\texport *\n}\n"
  },
  {
    "path": "Sources/PrivateFrameworks/include/StoreFoundation/ISAccountService-Protocol.h",
    "content": "//\n// Generated by https://github.com/blacktop/ipsw (Version: 3.1.660, BuildCommit: Homebrew)\n//\n// - LC_BUILD_VERSION:  Platform: macOS, MinOS: 26.2, SDK: 26.2, Tool: ld (1230.3)\n// - LC_SOURCE_VERSION: 716.2.2.0.0\n//\n\n@protocol ISAccountService <ISServiceRemoteObject>\n\n@required\n\n- (void)accountWithAppleID:(nullable NSString *)appleID replyBlock:(nonnull void (^)(ISStoreAccount * _Nullable))block; // Unverified appleID type / block parameter types\n- (void)accountWithDSID:(nullable NSNumber *)dsID replyBlock:(nonnull void (^)(ISStoreAccount * _Nullable))block; // Unverified dsID type / block parameter types\n- (void)addAccount:(nullable ISStoreAccount *)account; // Unverified account type\n- (void)addAccountStoreObserver:(nullable id <ISAccountStoreObserver>)observer; // Unverified observer type\n- (void)addURLBagObserver:(nullable id <ISURLBagObserver>)observer;\n- (void)authIsExpiredWithReplyBlock:(nonnull void (^)(BOOL))block; // Unverified block parameter types\n- (void)dictionaryForDSID:(nullable NSNumber *)dsID withReplyBlock:(nonnull void (^)(NSDictionary * _Nullable))block; // Unverified dsID type / block parameter types\n- (void)dictionaryWithReplyBlock:(nonnull void (^)(NSDictionary * _Nonnull))block; // Unverified block parameter types\n- (void)generateTouchIDHeadersForDSID:(nullable NSNumber *)dsID challenge:(nullable NSString *)challenge caller:(nullable id)caller replyBlock:(nonnull void (^)(NSDictionary * _Nonnull, NSError * _Nullable))block; // Unverified dsID type / challenge type / caller type / block parameter types\n- (void)getTouchIDPreferenceWithReplyBlock:(nonnull void (^)(BOOL, ISStoreAccount * _Nullable, NSError * _Nullable))block; // Unverified block parameter types\n- (void)httpHeadersForURL:(nullable NSURL *)url forDSID:(nullable NSNumber *)dsID includeADIHeaders:(BOOL)includeADIHeaders withReplyBlock:(nonnull void (^)(NSDictionary * _Nonnull))block; // Unverified url type / dsID type / block parameter types\n- (void)iCloudDSIDReplyBlock:(nonnull void (^)(NSString * _Nullable))block; // Unverified block parameter types\n- (void)invalidateAllBags;\n- (void)isValidWithReplyBlock:(nonnull void (^)(BOOL))block; // Unverified block parameter types\n- (void)loadURLBagWithType:(unsigned long long)type replyBlock:(nonnull void (^)(BOOL, BOOL, NSError * _Nullable))block; // Unverified block parameter types\n- (void)needsSilentADIActionForURL:(nullable NSURL *)url dsID:(nullable NSNumber *)dsID withReplyBlock:(nonnull void (^)(BOOL))block; // Unverified url type / dsID type / block parameter types\n- (void)needsSilentADIActionForURL:(nullable NSURL *)url withReplyBlock:(nonnull void (^)(BOOL))block; // Unverified url type / block parameter types\n- (void)primaryAccountWithReplyBlock:(nonnull void (^)(ISStoreAccount * _Nullable))block; // Unverified block parameter types\n- (void)processURLResponse:(nullable NSURLResponse *)urlResponse forRequest:(nullable NSURLRequest *)request; // Unverified urlResponse type / request type\n- (void)processURLResponse:(nullable NSURLResponse *)urlResponse forRequest:(nullable NSURLRequest *)request dsID:(nullable NSNumber *)dsID; // Unverified urlResponse type / request type / dsID type\n- (void)regexWithKey:(nullable NSString *)key dsID:(nullable NSNumber *)dsID matchesString:(nullable NSString *)string replyBlock:(nonnull void (^)(BOOL))block; // Unverified key type / dsID type / string type / block parameter types\n- (void)regexWithKey:(nullable NSString *)key matchesString:(nullable NSString *)string replyBlock:(nonnull void (^)(BOOL))block; // Unverified key type / string type / block parameter types\n- (void)removeAccountStoreObserver:(nullable id <ISAccountStoreObserver>)observer; // Unverified observer type\n- (void)removeURLBagObserver:(nullable id <ISURLBagObserver>)observer; // Unverified observer type\n- (void)retailStoreDemoModeReplyBlock:(nonnull void (^)(BOOL, NSString * _Nullable, NSString * _Nullable, BOOL))block; // Unverified block parameter types\n- (void)setStoreFrontID:(nullable NSString *)storefrontID; // Unverified storefrontID type\n- (void)setTouchIDState:(long long)touchIDState forDSID:(nullable NSNumber *)dsID replyBlock:(nonnull void (^)(BOOL, NSError * _Nullable))block; // Unverified dsID type / block parameter types\n- (void)shouldSendGUIDWithRequestForURL:(nullable NSURL *)url withReplyBlock:(nonnull void (^)(BOOL))block; // Unverified url type / block parameter types\n- (void)signOut;\n- (void)storeFrontWithReplyBlock:(nonnull void (^)(NSString * _Nonnull))block; // Unverified block parameter types\n- (void)updateTouchIDSettingsForDSID:(nullable NSNumber *)dsID replyBlock:(nonnull void (^)(BOOL, NSError * _Nullable))block; // Unverified dsID type / block parameter types\n- (void)urlIsTrustedByURLBag:(nullable NSURL *)urlBag dsID:(nullable NSNumber *)dsID withReplyBlock:(nonnull void (^)(BOOL))block; // Unverified urlBag type / dsID type / block parameter types\n- (void)urlIsTrustedByURLBag:(nullable NSURL *)urlBag withReplyBlock:(nonnull void (^)(BOOL))block; // Unverified urlBag type / block parameter types\n- (void)valueForURLBagKey:(nullable NSString *)bagKey dsID:(nullable NSNumber *)dsID withReplyBlock:(nonnull void (^)(NSURL * _Nullable))block; // Unverified bagKey type / dsID type / block parameter types\n- (void)valueForURLBagKey:(nullable NSString *)bagKey withReplyBlock:(nonnull void (^)(NSURL * _Nullable))block; // Unverified bagKey type / block parameter types\n\n@optional\n\n@end\n"
  },
  {
    "path": "Sources/PrivateFrameworks/include/StoreFoundation/ISServiceProxy.h",
    "content": "//\n// Generated by https://github.com/blacktop/ipsw (Version: 3.1.660, BuildCommit: Homebrew)\n//\n// - LC_BUILD_VERSION:  Platform: macOS, MinOS: 26.2, SDK: 26.2, Tool: ld (1230.3)\n// - LC_SOURCE_VERSION: 716.2.2.0.0\n//\n\n@interface ISServiceProxy : NSObject\n\n+ (nonnull instancetype)genericSharedProxy;\n+ (void)initialize;\n\n@property (readonly, nonatomic, nonnull) id <ISAccountService> accountService;\n@property (readonly, nonatomic, nonnull) id <ISAssetService> assetService;\n@property (readonly, nonatomic, nonnull) id <ISDownloadService> downloadService;\n@property (readonly, nonatomic, weak, nullable) id <ISServiceRemoteObject> exportedObject;\n@property (readonly, nonatomic, nullable) Protocol *exportedProtocol;\n@property (retain, nonatomic, nullable) ISStoreClient *storeClient;\n@property (readonly, nonatomic, nonnull) id <ISTransactionService> transactionService;\n@property (readonly, nonatomic, nonnull) id <ISUIService> uiService;\n\n- (void)accountServiceSynchronousBlock:(nonnull UnknownBlock)block;\n- (nonnull id <ISAccountService>)accountServiceWithErrorHandler:(nullable UnknownBlock)handler;\n- (void)assetServiceSynchronousBlock:(nonnull UnknownBlock)block;\n- (nonnull id <ISAssetService>)assetServiceWithErrorHandler:(nullable UnknownBlock)handler;\n- (void)connectionWasInterrupted;\n- (nonnull NSXPCConnection *)connectionWithServiceName:(nonnull NSString *)serviceName protocol:(nonnull Protocol *)protocol isMachService:(BOOL)isMachService;\n- (void)downloadServiceSynchronousBlock:(nonnull UnknownBlock)block;\n- (nonnull id <ISDownloadService>)downloadServiceWithErrorHandler:(nullable UnknownBlock)handler;\n- (nonnull instancetype)initWithStoreClient:(nullable ISStoreClient *)client; // Unverified client type\n- (nonnull id)objectProxyForServiceName:(nonnull NSString *)serviceName protocol:(nonnull id)protocol interfaceClassName:(nullable NSString *)interfaceClassName isMachService:(BOOL)isMachService errorHandler:(nullable UnknownBlock)handler;\n- (void)performSynchronousBlock:(nonnull UnknownBlock)block withServiceName:(nonnull NSString *)serviceName protocol:(nonnull Protocol *)protocol isMachService:(BOOL)isMachService interfaceClassName:(nullable NSString *)interfaceClassName;\n- (void)registerForInterrptionNotification;\n- (void)transactionServiceSynchronousBlock:(nonnull UnknownBlock)block;\n- (nonnull id <ISTransactionService>)transactionServiceWithErrorHandler:(nullable UnknownBlock)handler;\n- (void)uiServiceSynchronousBlock:(nonnull UnknownBlock)block;\n- (nonnull id <ISUIService>)uiServiceWithErrorHandler:(nullable UnknownBlock)handler;\n\n@end\n"
  },
  {
    "path": "Sources/PrivateFrameworks/include/StoreFoundation/ISStoreAccount.h",
    "content": "//\n// Generated by https://github.com/blacktop/ipsw (Version: 3.1.660, BuildCommit: Homebrew)\n//\n// - LC_BUILD_VERSION:  Platform: macOS, MinOS: 26.2, SDK: 26.2, Tool: ld (1230.3)\n// - LC_SOURCE_VERSION: 716.2.2.0.0\n//\n\n@interface ISStoreAccount : NSObject <NSSecureCoding> {\n\tNSTimer *_tokenInvalidTimer;\n}\n\n+ (nullable NSNumber *)dsidFromPlistValue:(nullable id)value;\n+ (nonnull NSDictionary *)migratePersistedStoreDictionary:(nullable NSDictionary *)dictionary;\n+ (BOOL)supportsSecureCoding;\n\n@property long long URLBagType;\n@property (readonly, getter=isAuthenticated) BOOL authenticated;\n@property (copy, nullable) NSString *creditString;\n@property (copy, nullable) NSNumber *dsID;\n@property (copy, nullable) NSString *identifier;\n@property BOOL isManagedStudent;\n@property BOOL isSignedIn;\n@property long long kind;\n@property (copy, nullable) NSString *password;\n@property (readonly, getter=isPrimary) BOOL primary;\n@property (retain, nullable) NSString *storeFront;\n@property (copy, nullable) NSString *token;\n@property (retain, nullable) NSTimer *tokenExpirationTimer;\n@property (retain, nullable) NSDate *tokenIssuedDate;\n@property long long touchIDState;\n\n- (nonnull NSString *)description;\n- (void)encodeWithCoder:(nullable NSCoder *)coder;\n- (long long)getTouchIDState;\n- (BOOL)hasValidStrongToken;\n- (nonnull instancetype)initWithCoder:(nullable NSCoder *)coder;\n- (nonnull instancetype)initWithPersistedStoreDictionary:(nullable NSDictionary *)dictionary;\n- (void)mergeValuesFromAuthenticationResponse:(nullable ISAuthenticationResponse *)response;\n- (nonnull NSDictionary<NSString *, NSNumber *> *)persistedStoreDictionary;\n- (void)resetTouchIDState;\n- (double)strongTokenValidForSecond;\n\n@end\n"
  },
  {
    "path": "Sources/PrivateFrameworks/include/StoreFoundation/SSDownload.h",
    "content": "//\n// Generated by https://github.com/blacktop/ipsw (Version: 3.1.660, BuildCommit: Homebrew)\n//\n// - LC_BUILD_VERSION:  Platform: macOS, MinOS: 26.2, SDK: 26.2, Tool: ld (1230.3)\n// - LC_SOURCE_VERSION: 716.2.2.0.0\n//\n\n@interface SSDownload : NSObject <NSSecureCoding> {\n\tBOOL _needsPreInstallValidation;\n}\n\n+ (BOOL)supportsSecureCoding;\n\n@property (copy, nullable) NSNumber *accountDSID;\n@property (copy, nonatomic, nullable) NSArray<SSDownloadAsset *> *assets; // Unverified generic type\n@property (copy, nullable) NSString *cancelURLString;\n@property (copy, nullable) NSString *customDownloadPath;\n@property BOOL didAutoUpdate;\n@property unsigned long long downloadType;\n@property BOOL installAfterLogout;\n@property (copy, nullable) NSString *installPath;\n@property BOOL isInServerQueue;\n@property (copy, nonatomic, nullable) SSDownloadMetadata *metadata;\n@property BOOL needsDisplayInDock;\n@property (copy, nullable) NSURL *relaunchAppWithBundleURL;\n@property BOOL skipAssetDownloadIfNotAlreadyOnDisk;\n@property BOOL skipInstallPhase;\n@property (retain, nonatomic, nullable) SSDownloadStatus *status;\n\n- (void)cancel;\n- (void)cancelWithPrompt:(BOOL)prompt;\n- (void)cancelWithPrompt:(BOOL)prompt storeClient:(nullable ISStoreClient *)client;\n- (void)cancelWithStoreClient:(nullable ISStoreClient *)client;\n- (void)encodeWithCoder:(nullable NSCoder *)coder;\n- (nonnull instancetype)init;\n- (nonnull instancetype)initWithAssets:(nullable NSArray<SSDownloadAsset *> *)assets metadata:(nullable SSDownloadMetadata *)metadata; // Unverified assets type / metadata type\n- (nonnull instancetype)initWithCoder:(nullable NSCoder *)coder;\n- (BOOL)isEqual:(nullable id)object;\n- (void)pause;\n- (void)pauseWithStoreClient:(nullable ISStoreClient *)client;\n- (nullable SSDownloadAsset *)primaryAsset;\n- (void)resume;\n- (void)resumeWithStoreClient:(nullable ISStoreClient *)client;\n- (void)setUseUniqueDownloadFolder:(BOOL)useUniqueDownloadFolder;\n\n@end\n"
  },
  {
    "path": "Sources/PrivateFrameworks/include/StoreFoundation/SSDownloadMetadata.h",
    "content": "//\n// Generated by https://github.com/blacktop/ipsw (Version: 3.1.660, BuildCommit: Homebrew)\n//\n// - LC_BUILD_VERSION:  Platform: macOS, MinOS: 26.2, SDK: 26.2, Tool: ld (1230.3)\n// - LC_SOURCE_VERSION: 716.2.2.0.0\n//\n\n@interface SSDownloadMetadata : NSObject <NSSecureCoding, NSCopying> {\n\tNSLock *_lock;\n}\n\n+ (BOOL)supportsSecureCoding;\n\n@property (readonly, nonnull) NSNumber *ageRestriction;\n@property BOOL animationExpected;\n@property (retain, nullable) NSString *appleID;\n@property (readonly, nonnull) NSString *applicationIdentifier;\n@property BOOL artworkIsPrerendered;\n@property (readonly, nonnull) NSArray<SSDownloadAsset *> *assets; // Unverified generic type\n@property (readonly, nullable) NSString *bundleDisplayName;\n@property (retain, nullable) NSString *bundleIdentifier;\n@property (readonly, nullable) NSString *bundleShortVersionString;\n@property (retain, nullable) NSString *bundleVersion;\n@property (retain, nullable) NSString *buyParameters;\n@property (readonly, nullable) NSNumber *collectionID;\n@property (retain, nullable) NSString *collectionName;\n@property (retain, nullable) NSDictionary *dictionary;\n@property (retain, nullable) NSString *downloadKey;\n@property (retain, nullable) NSNumber *durationInMilliseconds;\n@property (retain, nullable) NSData *epubRightsData;\n@property (readonly) BOOL extractionCanBeStreamed;\n@property (retain, nullable) NSString *fileExtension;\n@property (retain, nullable) NSString *genre;\n@property (readonly, nullable) NSNumber *iapContentSize;\n@property (readonly, nullable) NSString *iapContentVersion;\n@property (retain, nullable) NSString *iapInstallPath;\n@property (retain, nullable) NSData *ipaInstallBookmarkData NS_AVAILABLE_MAC(14);\n@property (retain, nullable) NSString *ipaInstallPath;\n@property (readonly) BOOL isExplicitContents;\n@property BOOL isMDMProvided;\n@property unsigned long long itemIdentifier;\n@property (retain, nullable) NSString *kind;\n@property (retain, nullable) NSString *managedAppUUIDString;\n@property (readonly) BOOL needsSoftwareInstallOperation;\n@property (retain, nullable) NSURL *preflightPackageURL;\n@property (retain, nullable) NSString *productType;\n@property (readonly, nullable) NSString *purchaseDate;\n@property (getter=isRental) BOOL rental;\n@property (readonly, getter=isSample) BOOL sample;\n@property (retain, nullable) NSArray<NSMutableDictionary<NSString *, id> *> *sinfs;\n@property (readonly, nullable) NSString *sortArtist;\n@property (readonly, nullable) NSString *sortName;\n@property (retain, nullable) NSString *subtitle;\n@property (retain, nullable) NSURL *thumbnailImageURL;\n@property (retain, nullable) NSString *title;\n@property (retain, nullable) NSString *transactionIdentifier;\n@property (readonly, nullable) NSNumber *uncompressedSize;\n@property (retain, nullable) NSNumber *version;\n\n- (nullable id)_valueForFirstAvailableKey:(nullable id)key;\n- (nonnull instancetype)copyWithZone:(nullable struct _NSZone *)zone;\n- (nullable NSDictionary *)deltaPackages; // Unverified return type\n- (void)encodeWithCoder:(nullable NSCoder *)coder;\n- (nonnull instancetype)init;\n- (nonnull instancetype)initWithCoder:(nullable NSCoder *)coder;\n- (nonnull instancetype)initWithDictionary:(nullable NSDictionary *)dictionary;\n- (nonnull instancetype)initWithKind:(nullable NSString *)kind;\n- (nullable id)localServerInfo;\n- (void)setValue:(nullable id)value forMetadataKey:(nonnull NSString *)key; // Unverified key type\n\n@end\n"
  },
  {
    "path": "Sources/PrivateFrameworks/include/StoreFoundation/SSDownloadPhase.h",
    "content": "//\n// Generated by https://github.com/blacktop/ipsw (Version: 3.1.660, BuildCommit: Homebrew)\n//\n// - LC_BUILD_VERSION:  Platform: macOS, MinOS: 26.2, SDK: 26.2, Tool: ld (1230.3)\n// - LC_SOURCE_VERSION: 716.2.2.0.0\n//\n\n@interface SSDownloadPhase : NSObject <NSSecureCoding, NSCopying>\n\n+ (BOOL)supportsSecureCoding;\n\n@property (readonly) double estimatedSecondsRemaining;\n@property (readonly, nullable) SSOperationProgress *operationProgress;\n@property (readonly) long long phaseType;\n@property (readonly) float progressChangeRate;\n@property (readonly) long long progressUnits;\n@property (readonly) long long progressValue;\n@property (readonly) long long totalProgressValue;\n\n- (nonnull instancetype)copyWithZone:(nullable struct _NSZone *)zone;\n- (void)encodeWithCoder:(nullable NSCoder *)coder;\n- (nonnull instancetype)init;\n- (nonnull instancetype)initWithCoder:(nullable NSCoder *)coder; // Unverified coder type\n- (nonnull instancetype)initWithOperationProgress:(nullable SSOperationProgress *)progress; // Unverified progress type\n\n@end\n"
  },
  {
    "path": "Sources/PrivateFrameworks/include/StoreFoundation/SSDownloadStatus.h",
    "content": "//\n// Generated by https://github.com/blacktop/ipsw (Version: 3.1.660, BuildCommit: Homebrew)\n//\n// - LC_BUILD_VERSION:  Platform: macOS, MinOS: 26.2, SDK: 26.2, Tool: ld (1230.3)\n// - LC_SOURCE_VERSION: 716.2.2.0.0\n//\n\n@interface SSDownloadStatus : NSObject <NSSecureCoding>\n\n+ (BOOL)supportsSecureCoding;\n\n@property (readonly, nonatomic, nullable) SSDownloadPhase *activePhase;\n@property (nonatomic, getter=isCancelled) BOOL cancelled;\n@property (retain, nonatomic, nullable) NSError *error;\n@property (nonatomic, getter=isFailed) BOOL failed;\n@property (readonly, nonatomic, getter=isPausable) BOOL pausable;\n@property (nonatomic, getter=isPaused) BOOL paused;\n@property (readonly, nonatomic) float percentComplete;\n@property (readonly, nonatomic) float phasePercentComplete;\n@property (readonly, nonatomic) long long phaseTimeRemaining;\n@property BOOL waiting;\n\n- (nonnull instancetype)copyWithZone:(nullable struct _NSZone *)zone;\n- (void)encodeWithCoder:(nullable NSCoder *)coder;\n- (nonnull instancetype)initWithCoder:(nullable NSCoder *)coder;\n- (void)setOperationProgress:(nullable SSOperationProgress *)progress; // Unverified progress type\n\n@end\n"
  },
  {
    "path": "Sources/PrivateFrameworks/include/StoreFoundation/SSPurchase.h",
    "content": "//\n// Generated by https://github.com/blacktop/ipsw (Version: 3.1.660, BuildCommit: Homebrew)\n//\n// - LC_BUILD_VERSION:  Platform: macOS, MinOS: 26.2, SDK: 26.2, Tool: ld (1230.3)\n// - LC_SOURCE_VERSION: 716.2.2.0.0\n//\n\n@interface SSPurchase : NSObject <NSSecureCoding, NSCopying>\n\n+ (nonnull instancetype)purchaseWithBuyParameters:(nullable NSString *)buyParameters; // Unverified buyParameters type\n+ (nonnull NSArray<NSArray<SSPurchase *> *> *)purchasesGroupedByAccountIdentifierWithPurchases:(nullable NSArray<SSPurchase *> *)purchases;\n+ (BOOL)supportsSecureCoding;\n\n@property (retain, nonatomic, nullable) NSNumber *accountIdentifier;\n@property (retain, nonatomic, nullable) NSString *appleID;\n@property (copy, nullable) UnknownBlock authFallbackHandler; // Unverified value type\n@property (copy, nonatomic, nullable) NSString *buyParameters;\n@property BOOL checkPreflightAterPurchase;\n@property (copy, nonatomic, nullable) SSDownloadMetadata *downloadMetadata;\n@property (retain, nullable) NSDictionary *dsidLessOptions;\n@property BOOL isCancelled;\n@property BOOL isDSIDLessPurchase;\n@property BOOL isRecoveryPurchase;\n@property BOOL isRedownload;\n@property BOOL isUpdate;\n@property BOOL isVPP;\n@property unsigned long long itemIdentifier;\n@property (retain, nonatomic, nullable) NSString *managedAppUUIDString;\n@property (readonly) BOOL needsAuthentication;\n@property (retain, nonatomic, nullable) NSString *parentalControls;\n@property (weak, nullable) ISOperation *purchaseOperation;\n@property (nonatomic) long long purchaseType;\n@property (retain, nonatomic, nullable) NSData *receiptData;\n@property (copy, nullable) NSDictionary *responseDialog;\n@property BOOL shouldBeInstalledAfterLogout;\n@property (readonly, nonatomic, nullable) NSString *sortableAccountIdentifier;\n@property (readonly, nonatomic, nonnull) NSString *uniqueIdentifier;\n\n- (nullable NSString *)_sortableAccountIdentifier;\n- (nonnull instancetype)copyWithZone:(nullable struct _NSZone *)zone;\n- (nonnull NSString *)description;\n- (void)encodeWithCoder:(nullable NSCoder *)coder;\n- (nonnull instancetype)initWithCoder:(nullable NSCoder *)coder;\n- (nonnull NSNumber *)productID;\n- (BOOL)purchaseDSIDMatchesPrimaryAccount;\n\n@end\n"
  },
  {
    "path": "Sources/PrivateFrameworks/include/StoreFoundation/SSPurchaseResponse.h",
    "content": "//\n// Generated by https://github.com/blacktop/ipsw (Version: 3.1.660, BuildCommit: Homebrew)\n//\n// - LC_BUILD_VERSION:  Platform: macOS, MinOS: 26.2, SDK: 26.2, Tool: ld (1230.3)\n// - LC_SOURCE_VERSION: 716.2.2.0.0\n//\n\n@interface SSPurchaseResponse : NSObject <NSSecureCoding> {\n\tNSDictionary *_rawResponse;\n}\n\n+ (BOOL)supportsSecureCoding;\n\n@property (retain, nullable) NSArray<SSDownload *> *downloads;\n@property (retain, nullable) NSDictionary<NSString *, id> *metrics;\n\n- (nonnull NSMutableArray<SSDownload *> *)_newDownloadsFromItems:(nullable NSArray<NSDictionary *> *)items withDSID:(nullable NSNumber *)dsID; // Unverified items element generic types / dsID type\n- (void)encodeWithCoder:(nullable NSCoder *)coder;\n- (nonnull instancetype)initWithCoder:(nullable NSCoder *)coder;\n- (nonnull instancetype)initWithDictionary:(nullable NSDictionary *)dictionary userIdentifier:(nullable NSString *)userIdentifier; // Unverified dictionary generic types / userIdentifier type\n\n@end\n"
  },
  {
    "path": "Sources/PrivateFrameworks/include/StoreFoundation/StoreFoundation.h",
    "content": "//\n// Generated by https://github.com/blacktop/ipsw (Version: 3.1.660, BuildCommit: Homebrew)\n//\n// - LC_BUILD_VERSION:  Platform: macOS, MinOS: 26.2, SDK: 26.2, Tool: ld (1230.3)\n// - LC_SOURCE_VERSION: 716.2.2.0.0\n//\n\n@import Foundation;\n\n@class ISAuthenticationContext, ISAuthenticationResponse, ISOperation, ISStoreClient, SSDownloadAsset, SSOperationProgress;\n\n@protocol ISAccountStoreObserver, ISAssetService, ISDownloadService, ISInAppService, ISServiceRemoteObject, ISTransactionService, ISUIService, ISURLBagObserver;\n\ntypedef void (^UnknownBlock)();\n\n#import \"ISStoreAccount.h\"\n#import \"ISAccountService-Protocol.h\"\n#import \"ISServiceProxy.h\"\n#import \"SSDownloadMetadata.h\"\n#import \"SSDownloadPhase.h\"\n#import \"SSDownloadStatus.h\"\n#import \"SSDownload.h\"\n#import \"SSPurchase.h\"\n#import \"SSPurchaseResponse.h\"\n"
  },
  {
    "path": "Sources/PrivateFrameworks/include/StoreFoundation/module.modulemap",
    "content": "module StoreFoundation [system] [no_undeclared_includes] {\n\trequires macos, objc\n\tuse Foundation\n\tlink framework \"StoreFoundation\"\n\tumbrella header \"StoreFoundation.h\"\n\texport *\n}\n"
  },
  {
    "path": "Sources/mas/AppStore/AppStoreAction+download.swift",
    "content": "//\n// AppStoreAction+download.swift\n// mas\n//\n// Copyright © 2015 mas-cli. All rights reserved.\n//\n\nprivate import CommerceKit\nprivate import CoreServices\nprivate import Foundation\nprivate import ObjectiveC\nprivate import StoreFoundation\n\nextension AppStoreAction { // swiftlint:disable:this file_types_order\n\t@MainActor\n\tfunc app(withADAMID adamID: ADAMID, shouldCancel: @escaping @Sendable (String?, Bool) -> Bool) async throws {\n\t\tlet purchase = SSPurchase(\n\t\t\tbuyParameters: \"\"\"\n\t\t\t\tproductType=C&price=0&pg=default&appExtVrsId=0&pricingParameters=\\\n\t\t\t\t\\(self == .get ? \"STDQ&macappinstalledconfirmed=1\" : \"STDRDL\")&salableAdamId=\\(adamID)\n\t\t\t\t\"\"\",\n\t\t)\n\n\t\t// Possibly unnecessary…\n\t\tpurchase.isRedownload = self != .get\n\t\tpurchase.isUpdate = self == .update\n\n\t\tpurchase.itemIdentifier = adamID\n\n\t\tlet downloadMetadata = SSDownloadMetadata(kind: \"software\")\n\t\tdownloadMetadata.itemIdentifier = adamID\n\t\tpurchase.downloadMetadata = downloadMetadata\n\n\t\tlet queue = CKDownloadQueue.shared()\n\t\tlet observer = DownloadQueueObserver(for: self, of: adamID, shouldCancel: shouldCancel)\n\t\tlet observerUUID = queue.add(observer)\n\t\tdefer {\n\t\t\tqueue.removeObserver(observerUUID)\n\t\t}\n\n\t\ttry await withCheckedThrowingContinuation { continuation in\n\t\t\tobserver.set(continuation: continuation)\n\n\t\t\tCKPurchaseController.shared().perform(purchase, withOptions: 0) { _, _, error, response in\n\t\t\t\tif let error {\n\t\t\t\t\tTask {\n\t\t\t\t\t\tawait observer.resumeOnce { $0.resume(throwing: error) }\n\t\t\t\t\t}\n\t\t\t\t} else if response?.downloads?.isEmpty != false {\n\t\t\t\t\tTask {\n\t\t\t\t\t\tawait observer.resumeOnce { continuation in\n\t\t\t\t\t\t\tcontinuation.resume(throwing: MASError.error(\"No downloads initiated for ADAM ID \\(adamID)\"))\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nprivate actor DownloadQueueObserver: CKDownloadQueueObserver {\n\tprivate let action: AppStoreAction\n\tprivate let adamID: ADAMID\n\tprivate let shouldCancel: @Sendable (String?, Bool) -> Bool\n\tprivate let downloadFolderURL: URL\n\n\tprivate nonisolated(unsafe) var continuation = CheckedContinuation<Void, any Error>?.none\n\n\tprivate var prevPhaseType = PhaseType.processing\n\tprivate var pkgHardLinkURL = URL?.none\n\tprivate var receiptHardLinkURL = URL?.none\n\tprivate var alreadyResumed = false\n\n\tinit(for action: AppStoreAction, of adamID: ADAMID, shouldCancel: @escaping @Sendable (String?, Bool) -> Bool) {\n\t\tself.action = action\n\t\tself.adamID = adamID\n\t\tself.shouldCancel = shouldCancel\n\t\tdownloadFolderURL = URL(filePath: \"\\(CKDownloadDirectory(nil))/\\(adamID)\", directoryHint: .isDirectory)\n\t}\n\n\tdeinit {\n\t\tresumeOnce(\n\t\t\talreadyResumed: alreadyResumed,\n\t\t\tpkgHardLinkURL: pkgHardLinkURL,\n\t\t\treceiptHardLinkURL: receiptHardLinkURL,\n\t\t) { continuation in\n\t\t\tcontinuation // swiftformat:disable:next indent\n\t\t\t.resume(throwing: MASError.error(\"Observer deallocated before download completed for ADAM ID \\(adamID)\"))\n\t\t}\n\t}\n\n\tnonisolated func set(continuation: CheckedContinuation<Void, any Error>) {\n\t\tunsafe self.continuation = continuation\n\t}\n\n\tnonisolated func downloadQueue(_: CKDownloadQueue, changedWithAddition _: SSDownload) {\n\t\t// Do nothing\n\t}\n\n\tnonisolated func downloadQueue(_ queue: CKDownloadQueue, statusChangedFor download: SSDownload) {\n\t\tguard\n\t\t\tlet snapshot = DownloadSnapshot(to: action, download),\n\t\t\tsnapshot.adamID == adamID,\n\t\t\t!snapshot.isCancelled,\n\t\t\t!snapshot.isFailed\n\t\telse {\n\t\t\treturn\n\t\t}\n\t\tguard !shouldCancel(snapshot.version, true) else {\n\t\t\tqueue.cancelDownload(download, promptToConfirm: false, askToDelete: false)\n\t\t\treturn\n\t\t}\n\n\t\tTask {\n\t\t\tawait statusChanged(for: snapshot)\n\t\t}\n\t}\n\n\tnonisolated func downloadQueue(_: CKDownloadQueue, changedWithRemoval download: SSDownload) {\n\t\tguard let snapshot = DownloadSnapshot(to: action, download), snapshot.adamID == adamID else {\n\t\t\treturn\n\t\t}\n\n\t\tTask {\n\t\t\tawait removed(snapshot)\n\t\t}\n\t}\n\n\tfunc resumeOnce(performing action: (CheckedContinuation<Void, any Error>) -> Void) {\n\t\tresumeOnce(\n\t\t\talreadyResumed: alreadyResumed,\n\t\t\tpkgHardLinkURL: pkgHardLinkURL,\n\t\t\treceiptHardLinkURL: receiptHardLinkURL,\n\t\t\tperforming: action,\n\t\t)\n\t\talreadyResumed = true\n\t}\n\n\tprivate nonisolated func resumeOnce(\n\t\talreadyResumed: Bool,\n\t\tpkgHardLinkURL: URL?,\n\t\treceiptHardLinkURL: URL?,\n\t\tperforming action: (CheckedContinuation<Void, any Error>) -> Void,\n\t) {\n\t\tguard !alreadyResumed else {\n\t\t\treturn\n\t\t}\n\t\tguard let continuation = unsafe continuation else {\n\t\t\tMAS.printer.error(\"Failed to obtain download continuation for ADAM ID \\(adamID)\")\n\t\t\treturn\n\t\t}\n\n\t\taction(continuation)\n\t\tdeleteTempFolder(containing: pkgHardLinkURL, fileType: \"pkg\")\n\t\tdeleteTempFolder(containing: receiptHardLinkURL, fileType: \"receipt\")\n\t}\n\n\tprivate func statusChanged(for snapshot: DownloadSnapshot) {\n\t\t// Refresh hard links to latest artifacts in the download directory\n\t\tdo {\n\t\t\tlet downloadFolderChildURLs = try FileManager.default.contentsOfDirectory(\n\t\t\t\tat: downloadFolderURL,\n\t\t\t\tincludingPropertiesForKeys: [.contentModificationDateKey, .isRegularFileKey],\n\t\t\t)\n\t\t\tdo {\n\t\t\t\tpkgHardLinkURL = try hardLinkURL(\n\t\t\t\t\tto: try downloadFolderChildURLs.compactMap { url in\n\t\t\t\t\t\tguard url.pathExtension == \"pkg\" else {\n\t\t\t\t\t\t\treturn nil as (url: URL, date: Date)?\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlet resourceValues = try url.resourceValues(forKeys: [.contentModificationDateKey, .isRegularFileKey])\n\t\t\t\t\t\treturn resourceValues.isRegularFile == true ? resourceValues.contentModificationDate.map { (url, $0) } : nil\n\t\t\t\t\t}\n\t\t\t\t\t.max { $0.date < $1.date }?\n\t\t\t\t\t.url,\n\t\t\t\t\texisting: pkgHardLinkURL,\n\t\t\t\t)\n\t\t\t} catch {\n\t\t\t\tMAS.printer.warning(\"Failed to link pkg for\", snapshot.appNameAndVersion, error: error)\n\t\t\t}\n\n\t\t\tdo {\n\t\t\t\treceiptHardLinkURL = try hardLinkURL(\n\t\t\t\t\tto: downloadFolderChildURLs.first { $0.lastPathComponent == \"receipt\" },\n\t\t\t\t\texisting: receiptHardLinkURL,\n\t\t\t\t)\n\t\t\t} catch {\n\t\t\t\tMAS.printer.warning(\"Failed to link receipt for\", snapshot.appNameAndVersion, error: error)\n\t\t\t}\n\t\t} catch {\n\t\t\tMAS.printer.warning(\n\t\t\t\t\"Failed to read contents of download folder\",\n\t\t\t\tdownloadFolderURL.filePath.quoted,\n\t\t\t\t\"for\",\n\t\t\t\tsnapshot.appNameAndVersion,\n\t\t\t\terror: error,\n\t\t\t)\n\t\t}\n\n\t\tswitch snapshot.activePhaseType {\n\t\tcase prevPhaseType:\n\t\t\tbreak\n\t\tcase\n\t\t\t.downloading where prevPhaseType == .processing,\n\t\t\t.downloaded where prevPhaseType == .downloading,\n\t\t\t.performing:\n\t\t\tMAS.printer.clearCurrentLine(of: .standardOutput)\n\t\t\tMAS.printer.notice(snapshot.activePhaseType, snapshot.appNameAndVersion)\n\t\tdefault:\n\t\t\tbreak\n\t\t}\n\n\t\tif\n\t\t\tFileHandle.standardOutput.isTerminal,\n\t\t\tsnapshot.phasePercentComplete != 0 || snapshot.activePhaseType != .processing\n\t\t{\n\t\t\t// Output the progress bar iff connected to a terminal\n\t\t\tlet totalLength = 60\n\t\t\tlet completedLength = Int(snapshot.phasePercentComplete * Float(totalLength))\n\t\t\tMAS.printer.clearCurrentLine(of: .standardOutput)\n\t\t\tMAS.printer.info(\n\t\t\t\tString(repeating: \"#\", count: completedLength),\n\t\t\t\tString(repeating: \"-\", count: totalLength - completedLength),\n\t\t\t\t\" \",\n\t\t\t\tUInt64((snapshot.phasePercentComplete * 100).rounded()),\n\t\t\t\t\"% \",\n\t\t\t\tsnapshot.activePhaseType.performed,\n\t\t\t\tseparator: \"\",\n\t\t\t\tterminator: \"\",\n\t\t\t)\n\t\t}\n\n\t\tprevPhaseType = snapshot.activePhaseType\n\t}\n\n\tprivate func removed(_ snapshot: DownloadSnapshot) async {\n\t\tMAS.printer.clearCurrentLine(of: .standardOutput)\n\n\t\tdo {\n\t\t\tlet appFolderURL: URL?\n\t\t\tif let error = snapshot.error {\n\t\t\t\tguard error is Ignorable else {\n\t\t\t\t\tthrow error\n\t\t\t\t}\n\n\t\t\t\tMAS.printer.notice(PhaseType.downloaded, snapshot.appNameAndVersion)\n\t\t\t\tMAS.printer.notice(action.performing.capitalizingFirstCharacter, snapshot.appNameAndVersion)\n\t\t\t\tMAS.printer.info(\n\t\t\t\t\tString(describing: action).capitalizingFirstCharacter,\n\t\t\t\t\t\"progress cannot be displayed\",\n\t\t\t\t\tterminator: \"\",\n\t\t\t\t)\n\t\t\t\tappFolderURL = try await install(appNameAndVersion: snapshot.appNameAndVersion)\n\t\t\t\tMAS.printer.clearCurrentLine(of: .standardOutput)\n\t\t\t} else {\n\t\t\t\tguard !snapshot.isFailed else {\n\t\t\t\t\tthrow MASError.error(\"Failed to download \\(snapshot.appNameAndVersion)\")\n\t\t\t\t}\n\t\t\t\tguard !shouldCancel(snapshot.version, false) else {\n\t\t\t\t\tresumeOnce { $0.resume() }\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tguard !snapshot.isCancelled else {\n\t\t\t\t\tthrow MASError.error(\"Download cancelled for \\(snapshot.appNameAndVersion)\")\n\t\t\t\t}\n\n\t\t\t\tappFolderURL = snapshot.appFolderPath.map { .init(filePath: $0, directoryHint: .isDirectory) }\n\t\t\t}\n\n\t\t\tMAS.printer.notice(\n\t\t\t\t[action.performed.capitalizingFirstCharacter, snapshot.appNameAndVersion]\n\t\t\t\t+ (appFolderURL.map { [\"in\", $0.filePath] } ?? []), // swiftformat:disable:this indent\n\t\t\t)\n\n\t\t\tif let appFolderURL {\n\t\t\t\tlet fileManager = FileManager.default\n\t\t\t\tif\n\t\t\t\t\ttry applicationsFolderURLs.contains(\n\t\t\t\t\t\twhere: { applicationsFolderURL in\n\t\t\t\t\t\t\tvar relationship = FileManager.URLRelationship.other\n\t\t\t\t\t\t\ttry unsafe fileManager.getRelationship(\n\t\t\t\t\t\t\t\t&relationship,\n\t\t\t\t\t\t\t\tofDirectoryAt: applicationsFolderURL,\n\t\t\t\t\t\t\t\ttoItemAt: appFolderURL,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn relationship == .contains\n\t\t\t\t\t\t},\n\t\t\t\t\t)\n\t\t\t\t{\n\t\t\t\t\tlet appFolderPath = appFolderURL.filePath\n\t\t\t\t\tlet installedApps = try await installedApps(withADAMID: snapshot.adamID).filter { $0.path != appFolderPath }\n\t\t\t\t\tif !installedApps.isEmpty {\n\t\t\t\t\t\tMAS.printer.warning(\n\t\t\t\t\t\t\t\"Multiple installations of \",\n\t\t\t\t\t\t\tsnapshot.name ?? \"unknown app\",\n\t\t\t\t\t\t\t\" exist in the applications folders\\n\\n\",\n\t\t\t\t\t\t\taction.performed.capitalizingFirstCharacter,\n\t\t\t\t\t\t\t\":\\n\",\n\t\t\t\t\t\t\tappFolderPath,\n\t\t\t\t\t\t\t\"\\n\\nOthers:\\n\",\n\t\t\t\t\t\t\tinstalledApps.map(\\.path).sorted(using: .localizedStandard).joined(separator: \"\\n\"),\n\t\t\t\t\t\t\tseparator: \"\",\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tMAS.printer.warning(\n\t\t\t\t\t\taction.performed.capitalizingFirstCharacter,\n\t\t\t\t\t\tsnapshot.appNameAndVersion,\n\t\t\t\t\t\t\"outside of the applications folders, in\",\n\t\t\t\t\t\tappFolderURL.filePath,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tresumeOnce { $0.resume() }\n\t\t} catch {\n\t\t\tresumeOnce { $0.resume(throwing: error) }\n\t\t}\n\t}\n\n\tprivate func hardLinkURL(to url: URL?, existing existingHardLinkURL: URL?) throws -> URL? {\n\t\tguard let url, try !url.linksToSameInode(as: existingHardLinkURL) else {\n\t\t\treturn existingHardLinkURL\n\t\t}\n\n\t\tlet fileManager = FileManager.default\n\t\tlet hardLinkURL = try fileManager.url(\n\t\t\tfor: .itemReplacementDirectory,\n\t\t\tin: .userDomainMask,\n\t\t\tappropriateFor: url,\n\t\t\tcreate: true,\n\t\t)\n\t\t.appending(path: \"\\(adamID)-\\(url.lastPathComponent)\", directoryHint: .notDirectory)\n\t\ttry fileManager.linkItem(at: url, to: hardLinkURL)\n\t\treturn hardLinkURL\n\t}\n\n\tprivate func install(appNameAndVersion: String) async throws -> URL {\n\t\tguard let pkgHardLinkPath = pkgHardLinkURL?.filePath else {\n\t\t\tthrow MASError.error(\"Failed to find pkg to \\(action) \\(appNameAndVersion)\")\n\t\t}\n\t\tguard let receiptHardLinkURL else {\n\t\t\tthrow MASError.error(\"Failed to find receipt to import for \\(appNameAndVersion)\")\n\t\t}\n\n\t\tlet (_, standardErrorString) = try await run(\n\t\t\t\"/usr/sbin/installer\",\n\t\t\t\"-dumplog\",\n\t\t\t\"-pkg\",\n\t\t\tpkgHardLinkPath,\n\t\t\t\"-target\",\n\t\t\t\"/\",\n\t\t\terrorMessage: \"Failed to \\(action) \\(appNameAndVersion) from \\(pkgHardLinkPath)\",\n\t\t) { process in try run(asEffectiveUID: 0, andEffectiveGID: 0) { try process.run() } }\n\n\t\tguard\n\t\t\tlet appFolderURLSubstring = standardErrorString\n\t\t\t.matches(of: unsafe appFolderURLRegex) // swiftformat:disable indent\n\t\t\t.compactMap(\\.1)\n\t\t\t.min(by: { $0.count < $1.count })\n\t\telse { // swiftformat:enable indent\n\t\t\tthrow MASError.error(\n\t\t\t\t\"Failed to find app folder URL in installer output for \\(appNameAndVersion)\",\n\t\t\t\terror: standardErrorString,\n\t\t\t)\n\t\t}\n\t\tguard let appFolderURL = URL(string: .init(appFolderURLSubstring)) else {\n\t\t\tthrow MASError.error(\n\t\t\t\t\"Failed to parse app folder URL for \\(appNameAndVersion) from \\(appFolderURLSubstring)\",\n\t\t\t\terror: standardErrorString,\n\t\t\t)\n\t\t}\n\n\t\tlet receiptURL = appFolderURL.appending(path: \"Contents/_MASReceipt/receipt\", directoryHint: .notDirectory)\n\t\tdo {\n\t\t\tlet fileManager = FileManager.default\n\t\t\ttry run(asEffectiveUID: 0, andEffectiveGID: 0) {\n\t\t\t\tif fileManager.fileExists(atPath: receiptURL.filePath) {\n\t\t\t\t\ttry fileManager.removeItem(at: receiptURL)\n\t\t\t\t} else {\n\t\t\t\t\ttry fileManager.createDirectory(\n\t\t\t\t\t\tat: receiptURL.deletingLastPathComponent(),\n\t\t\t\t\t\twithIntermediateDirectories: true,\n\t\t\t\t\t\tattributes: [.ownerAccountID: 0, .groupOwnerAccountID: 0, .posixPermissions: 0o755],\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\ttry fileManager.copyItem(at: receiptHardLinkURL, to: receiptURL)\n\t\t\t\ttry fileManager.setAttributes(\n\t\t\t\t\t[.ownerAccountID: 0, .groupOwnerAccountID: 0, .posixPermissions: 0o755],\n\t\t\t\t\tofItemAtPath: receiptURL.filePath,\n\t\t\t\t)\n\t\t\t}\n\t\t} catch {\n\t\t\tthrow MASError.error(\n\t\t\t\t\"\"\"\n\t\t\t\tFailed to copy receipt for \\(appNameAndVersion) from \\(receiptHardLinkURL.filePath.quoted) to\\\n\t\t\t\t \\(receiptURL.filePath.quoted)\n\t\t\t\t\"\"\",\n\t\t\t\terror: error,\n\t\t\t)\n\t\t}\n\n\t\t_ = try await run(\n\t\t\t\"/usr/bin/mdimport\",\n\t\t\tappFolderURL.filePath,\n\t\t\terrorMessage: \"Failed to \\(action) \\(appNameAndVersion) from \\(pkgHardLinkPath)\",\n\t\t)\n\n\t\tLSRegisterURL(appFolderURL as NSURL, true) // swiftlint:disable:this legacy_objc_type\n\n\t\treturn appFolderURL\n\t}\n}\n\nprivate struct DownloadSnapshot { // swiftlint:disable:this one_declaration_per_file\n\tlet adamID: ADAMID\n\tlet version: String?\n\tlet name: String?\n\tlet appNameAndVersion: String\n\tlet activePhaseType: PhaseType\n\tlet phasePercentComplete: Float\n\tlet appFolderPath: String?\n\tlet isCancelled: Bool\n\tlet isFailed: Bool\n\tlet error: (any Error)?\n\n\tinit?(to action: AppStoreAction, _ download: SSDownload) {\n\t\tguard let metadata = download.metadata, let status = download.status else {\n\t\t\treturn nil\n\t\t}\n\n\t\tadamID = metadata.itemIdentifier\n\t\tname = metadata.title\n\t\tversion = metadata.bundleVersion\n\t\tappNameAndVersion = \"\\(metadata.title ?? \"unknown app\") (\\(version ?? \"unknown version\"))\"\n\t\tactivePhaseType = PhaseType(action, rawValue: status.activePhase?.phaseType)\n\t\tphasePercentComplete = status.phasePercentComplete\n\t\tappFolderPath = download.installPath\n\t\tisCancelled = status.isCancelled\n\t\tisFailed = status.isFailed\n\t\terror = status.error.map { $0 as NSError }.map { error in\n\t\t\terror.domain == \"PKInstallErrorDomain\" && error.code == 201 ? Ignorable.installerWorkaround : error as any Error\n\t\t}\n\t}\n}\n\nprivate enum Ignorable: Error { // swiftlint:disable:this one_declaration_per_file\n\tcase installerWorkaround\n}\n\nprivate enum PhaseType: Equatable { // swiftlint:disable:this one_declaration_per_file\n\tcase processing // swiftlint:disable:this sorted_enum_cases\n\tcase downloading\n\tcase downloaded // swiftlint:disable:this sorted_enum_cases\n\tcase performing(AppStoreAction) // swiftlint:disable:this sorted_enum_cases\n\n\tvar performed: String {\n\t\tswitch self {\n\t\tcase .processing:\n\t\t\t\"processed\"\n\t\tcase // swiftformat:disable:this sortSwitchCases\n\t\t\t.downloading,\n\t\t\t.downloaded:\n\t\t\t\"downloaded\"\n\t\tcase let .performing(action):\n\t\t\taction.performed\n\t\t}\n\t}\n\n\tinit(_ action: AppStoreAction, rawValue: Int64?) {\n\t\tself =\n\t\t\tswitch rawValue {\n\t\t\tcase 0:\n\t\t\t\t.downloading\n\t\t\tcase 1:\n\t\t\t\t.performing(action)\n\t\t\tcase 5:\n\t\t\t\t.downloaded\n\t\t\tdefault:\n\t\t\t\t.processing\n\t\t\t}\n\t}\n}\n\nextension PhaseType: CustomStringConvertible {\n\tvar description: String {\n\t\tswitch self {\n\t\tcase .processing:\n\t\t\t\"Processing\"\n\t\tcase .downloading:\n\t\t\t\"Downloading\"\n\t\tcase .downloaded:\n\t\t\t\"Downloaded\"\n\t\tcase let .performing(action):\n\t\t\taction.performing\n\t\t}\n\t}\n}\n\nprivate extension String {\n\tvar capitalizingFirstCharacter: Self {\n\t\tprefix(1).capitalized + dropFirst()\n\t}\n}\n\nprivate extension URL {\n\tfunc linksToSameInode(as url: URL?) throws -> Bool {\n\t\tguard let url, url.isFileURL, isFileURL else {\n\t\t\treturn false\n\t\t}\n\t\tguard let fileID1 = try resourceValues(forKeys: [.fileResourceIdentifierKey]).fileResourceIdentifier else {\n\t\t\tthrow MASError.error(\"Failed to get file resource identifier for \\(filePath)\")\n\t\t}\n\t\tguard let fileID2 = try url.resourceValues(forKeys: [.fileResourceIdentifierKey]).fileResourceIdentifier else {\n\t\t\tthrow MASError.error(\"Failed to get file resource identifier for \\(url.filePath)\")\n\t\t}\n\n\t\treturn fileID1.isEqual(fileID2)\n\t}\n}\n\nprivate func deleteTempFolder(containing url: URL?, fileType: String) {\n\turl.map { url in\n\t\tdo {\n\t\t\ttry FileManager.default.removeItem(at: url.deletingLastPathComponent())\n\t\t} catch {\n\t\t\tMAS.printer.warning(\"Failed to delete temp folder containing\", fileType, url.filePath, error: error)\n\t\t}\n\t}\n}\n\nprivate nonisolated(unsafe) let appFolderURLRegex = /PackageKit: Registered bundle (\\S+) for uid 0/\n"
  },
  {
    "path": "Sources/mas/AppStore/AppStoreAction.swift",
    "content": "//\n// AppStoreAction.swift\n// mas\n//\n// Copyright © 2015 mas-cli. All rights reserved.\n//\n\nprivate import ArgumentParser\nprivate import Darwin\nprivate import OrderedCollections\nprivate import StoreFoundation\n\nenum AppStoreAction {\n\tcase get\n\tcase install\n\tcase update\n\n\tvar performed: String {\n\t\tswitch self {\n\t\tcase .get:\n\t\t\t\"got\"\n\t\tcase .install:\n\t\t\t\"installed\"\n\t\tcase .update:\n\t\t\t\"updated\"\n\t\t}\n\t}\n\n\tvar performing: String {\n\t\tswitch self {\n\t\tcase .get:\n\t\t\t\"getting\"\n\t\tcase .install:\n\t\t\t\"installing\"\n\t\tcase .update:\n\t\t\t\"updating\"\n\t\t}\n\t}\n\n\tfunc apps(\n\t\twithAppIDs appIDs: [AppID],\n\t\tforce: Bool,\n\t\tinstalledApps: [InstalledApp],\n\t\tlookupAppFromAppID: @escaping @Sendable (AppID) async throws -> CatalogApp,\n\t) async throws {\n\t\ttry await apps(\n\t\t\twithADAMIDs: await appIDs.lookupCatalogApps(using: lookupAppFromAppID).map(\\.adamID),\n\t\t\tforce: force,\n\t\t\tinstalledApps: installedApps,\n\t\t)\n\t}\n\n\tfunc apps(withADAMIDs adamIDs: [ADAMID], force: Bool, installedApps: [InstalledApp]) async throws {\n\t\ttry await apps(\n\t\t\twithADAMIDs: adamIDs.filter { adamID in\n\t\t\t\tif !force, let installedApp = installedApps.first(where: { $0.adamID == adamID }) {\n\t\t\t\t\tMAS.printer.warning(\"Already \", performed, \" \", installedApp.name, \" (\", adamID, \")\", separator: \"\")\n\t\t\t\t\treturn false\n\t\t\t\t}\n\n\t\t\t\treturn true\n\t\t\t},\n\t\t)\n\t}\n\n\tfunc apps(withADAMIDs adamIDs: [ADAMID]) async throws {\n\t\tguard !adamIDs.isEmpty else {\n\t\t\treturn\n\t\t}\n\n\t\tlet adamIDs = OrderedSet(adamIDs)\n\t\tguard getuid() == 0 else {\n\t\t\ttry sudo(MAS._commandName, args: [String(describing: self), \"--force\"] + adamIDs.map(String.init(describing:)))\n\t\t\treturn\n\t\t}\n\n\t\tawait adamIDs.forEach(attemptTo: \"\\(self) app for ADAM ID\") { adamID in\n\t\t\ttry await app(withADAMID: adamID) { _, _ in false }\n\t\t}\n\t}\n}\n\ntypealias AppStore = AppStoreAction\n"
  },
  {
    "path": "Sources/mas/AppStore/Region.swift",
    "content": "//\n// Region.swift\n// mas\n//\n// Copyright © 2024 mas-cli. All rights reserved.\n//\n\nprivate import Foundation\n\ntypealias Region = String\n\nprivate extension Region {\n\tvar appStoreRegion: Self {\n\t\tswitch self { // swiftlint:disable switch_case_on_newline\n\t\tcase \"AD\": \"ES\" // Andorra                                      > Spain\n\t\tcase \"AQ\": \"NO\" // Antarctica                                   > Norway\n\t\tcase \"AS\": \"US\" // American Samoa                               > United States\n\t\tcase \"AW\": \"NL\" // Aruba                                        > Netherlands\n\t\tcase \"AX\": \"FI\" // Åland Islands                                > Finland\n\t\tcase \"BD\": \"IN\" // Bangladesh                                   > India\n\t\tcase \"BI\": \"KE\" // Burundi                                      > Kenya\n\t\tcase \"BL\": \"FR\" // St. Barthélemy                               > France\n\t\tcase \"BQ\": \"NL\" // Bonaire, Sint Eustatius and Saba             > Netherlands\n\t\tcase \"BV\": \"NO\" // Bouvet Island                                > Norway\n\t\tcase \"CC\": \"AU\" // Cocos (Keeling) Islands                      > Australia\n\t\tcase \"CF\": \"FR\" // Central African Republic                     > France\n\t\tcase \"CK\": \"NZ\" // Cook Islands                                 > New Zealand\n\t\tcase \"CU\": \"US\" // Cuba                                         > United States\n\t\tcase \"CW\": \"NL\" // Curaçao                                      > Netherlands\n\t\tcase \"CX\": \"AU\" // Christmas Island                             > Australia\n\t\tcase \"DJ\": \"FR\" // Djibouti                                     > France\n\t\tcase \"EH\": \"MA\" // Western Sahara                               > Morocco\n\t\tcase \"ER\": \"KE\" // Eritrea                                      > Kenya\n\t\tcase \"ET\": \"KE\" // Ethiopia                                     > Kenya\n\t\tcase \"FK\": \"GB\" // Falkland Islands                             > United Kingdom\n\t\tcase \"FO\": \"DK\" // Faroe Islands                                > Denmark\n\t\tcase \"GF\": \"FR\" // French Guiana                                > France\n\t\tcase \"GG\": \"GB\" // Guernsey                                     > United Kingdom\n\t\tcase \"GI\": \"GB\" // Gibraltar                                    > United Kingdom\n\t\tcase \"GL\": \"DK\" // Greenland                                    > Denmark\n\t\tcase \"GN\": \"FR\" // Guinea                                       > France\n\t\tcase \"GP\": \"FR\" // Guadeloupe                                   > France\n\t\tcase \"GQ\": \"FR\" // Equatorial Guinea                            > France\n\t\tcase \"GS\": \"GB\" // South Georgia and the South Sandwich Islands > United Kingdom\n\t\tcase \"GU\": \"US\" // Guam                                         > United States\n\t\tcase \"HM\": \"AU\" // Heard Island and McDonald Islands            > Australia\n\t\tcase \"HT\": \"US\" // Haiti                                        > United States\n\t\tcase \"IC\": \"ES\" // Canary Islands                               > Spain\n\t\tcase \"IM\": \"GB\" // Isle of Man                                  > United Kingdom\n\t\tcase \"IO\": \"GB\" // British Indian Ocean Territory               > United Kingdom\n\t\tcase \"IR\": \"TR\" // Iran                                         > Türkiye\n\t\tcase \"JE\": \"GB\" // Jersey                                       > United Kingdom\n\t\tcase \"KI\": \"AU\" // Kiribati                                     > Australia\n\t\tcase \"KM\": \"FR\" // Comoros                                      > France\n\t\tcase \"KP\": \"CN\" // Korea, Democratic People's Republic of       > China\n\t\tcase \"LI\": \"CH\" // Liechtenstein                                > Switzerland\n\t\tcase \"LS\": \"ZA\" // Lesotho                                      > South Africa\n\t\tcase \"MC\": \"FR\" // Monaco                                       > France\n\t\tcase \"MF\": \"FR\" // St. Martin                                   > France\n\t\tcase \"MH\": \"US\" // Marshall Islands                             > United States\n\t\tcase \"MP\": \"US\" // Northern Mariana Islands                     > United States\n\t\tcase \"MQ\": \"FR\" // Martinique                                   > France\n\t\tcase \"NC\": \"FR\" // New Caledonia                                > France\n\t\tcase \"NF\": \"AU\" // Norfolk Island                               > Australia\n\t\tcase \"NU\": \"NZ\" // Niue                                         > New Zealand\n\t\tcase \"PF\": \"FR\" // French Polynesia                             > France\n\t\tcase \"PM\": \"FR\" // St. Pierre and Miquelon                      > France\n\t\tcase \"PN\": \"NZ\" // Pitcairn Islands                             > New Zealand\n\t\tcase \"PR\": \"US\" // Puerto Rico                                  > United States\n\t\tcase \"PS\": \"IL\" // Palestine                                    > Israel\n\t\tcase \"RE\": \"FR\" // Réunion                                      > France\n\t\tcase \"SD\": \"EG\" // Sudan                                        > Egypt\n\t\tcase \"SH\": \"GB\" // St. Helena, Ascension and Tristan da Cunha   > United Kingdom\n\t\tcase \"SJ\": \"NO\" // Svalbard and Jan Mayen                       > Norway\n\t\tcase \"SM\": \"IT\" // San Marino                                   > Italy\n\t\tcase \"SO\": \"KE\" // Somalia                                      > Kenya\n\t\tcase \"SS\": \"KE\" // South Sudan                                  > Kenya\n\t\tcase \"SX\": \"NL\" // Sint Maarten                                 > Netherlands\n\t\tcase \"SY\": \"TR\" // Syria                                        > Türkiye\n\t\tcase \"TF\": \"FR\" // French Southern Territories                  > France\n\t\tcase \"TG\": \"FR\" // Togo                                         > France\n\t\tcase \"TK\": \"NZ\" // Tokelau                                      > New Zealand\n\t\tcase \"TL\": \"ID\" // Timor-Leste                                  > Indonesia\n\t\tcase \"TV\": \"AU\" // Tuvalu                                       > Australia\n\t\tcase \"UM\": \"US\" // United States Minor Outlying Islands         > United States\n\t\tcase \"VA\": \"IT\" // Vatican City State                           > Italy\n\t\tcase \"VI\": \"US\" // Virgin Islands of the United States          > United States\n\t\tcase \"WF\": \"FR\" // Wallis and Futuna                            > France\n\t\tcase \"WS\": \"AU\" // Samoa                                        > Australia\n\t\tcase \"YT\": \"FR\" // Mayotte                                      > France\n\t\tdefault: self // swiftlint:enable switch_case_on_newline\n\t\t}\n\t}\n}\n\nvar appStoreRegion: Region {\n\tmacRegion.appStoreRegion\n}\n\nvar macRegion: Region {\n\tLocale.current.region?.identifier ?? \"US\"\n}\n"
  },
  {
    "path": "Sources/mas/Commands/Config.swift",
    "content": "//\n// Config.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\ninternal import ArgumentParser\nprivate import Darwin\nprivate import Foundation\n\nextension MAS {\n\t/// Outputs mas config & related system info.\n\tstruct Config: ParsableCommand {\n\t\tstatic let configuration = CommandConfiguration(\n\t\t\tabstract: \"Output mas config & related system info\",\n\t\t)\n\n\t\tfunc run() {\n\t\t\tprinter.info(\n\t\t\t\t\"\"\"\n\t\t\t\tmas ▁▁▁▁ \\(version)\n\t\t\t\tslice ▁▁ \\(runningSliceArchitecture)\n\t\t\t\tslices ▁ \\(supportedSliceArchitectures.joined(separator: \" \"))\n\t\t\t\tdist ▁▁▁ \\(distribution)\n\t\t\t\torigin ▁ \\(gitOrigin)\n\t\t\t\trev ▁▁▁▁ \\(gitRevision)\n\t\t\t\tswift ▁▁ \\(swiftVersion)\n\t\t\t\tdriver ▁ \\(swiftDriverVersion)\n\t\t\t\tstore ▁▁ \\(appStoreRegion)\n\t\t\t\tregion ▁ \\(macRegion)\n\t\t\t\tmacos ▁▁ \\(macOSVersion)\n\t\t\t\tmac ▁▁▁▁ \\(configStringValue(\"hw.product\"))\n\t\t\t\tcpu ▁▁▁▁ \\(configStringValue(\"machdep.cpu.brand_string\"))\n\t\t\t\tarch ▁▁▁ \\(configStringValue(\"hw.machine\"))\n\t\t\t\t\"\"\",\n\t\t\t)\n\t\t}\n\t}\n}\n\nprivate var runningSliceArchitecture: String {\n\tvar info = utsname()\n\treturn unsafe uname(&info) == 0\n\t? withUnsafePointer(to: &info.machine) { pointer in // swiftformat:disable indent\n\t\tunsafe pointer.withMemoryRebound(\n\t\t\tto: CChar.self,\n\t\t\tcapacity: unsafe MemoryLayout.size(ofValue: unsafe pointer),\n\t\t\tunsafe String.init(cString:),\n\t\t)\n\t}\n\t: unknown\n} // swiftformat:enable indent\n\nprivate var supportedSliceArchitectures: [String] {\n\tBundle.main.executableArchitectures.map { archIDs in\n\t\tarchIDs.map { archID in\n\t\t\tguard let arch = Int(exactly: archID) else {\n\t\t\t\treturn \"unknown_\\(archID)\"\n\t\t\t}\n\n\t\t\treturn switch arch {\n\t\t\tcase NSBundleExecutableArchitectureARM64:\n\t\t\t\t\"arm64\"\n\t\t\tcase NSBundleExecutableArchitectureI386:\n\t\t\t\t\"i386\"\n\t\t\tcase NSBundleExecutableArchitecturePPC:\n\t\t\t\t\"ppc\"\n\t\t\tcase NSBundleExecutableArchitecturePPC64:\n\t\t\t\t\"ppc64\"\n\t\t\tcase NSBundleExecutableArchitectureX86_64:\n\t\t\t\t\"x86_64\"\n\t\t\tdefault:\n\t\t\t\t\"unknown_0x\\(String(arch, radix: 16))\"\n\t\t\t}\n\t\t}\n\t}\n\t?? [] // swiftformat:disable:this indent\n}\n\nprivate var macOSVersion: Substring {\n\tProcessInfo.processInfo.operatingSystemVersionString.dropFirst(8).replacing(\"Build \", with: \"\", maxReplacements: 1)\n}\n\nprivate func configStringValue(_ name: String) -> String {\n\tvar size = 0\n\tguard unsafe sysctlbyname(name, nil, &size, nil, 0) == 0 else {\n\t\tunsafe perror(sysCtlByName)\n\t\treturn unknown\n\t}\n\n\tvar buffer = [CChar](repeating: 0, count: size)\n\tguard unsafe sysctlbyname(name, &buffer, &size, nil, 0) == 0 else {\n\t\tunsafe perror(sysCtlByName)\n\t\treturn unknown\n\t}\n\n\treturn unsafe String(cString: &buffer)\n}\n\nprivate let unknown = \"unknown\"\nprivate let sysCtlByName = \"sysctlbyname\"\n"
  },
  {
    "path": "Sources/mas/Commands/Get.swift",
    "content": "//\n// Get.swift\n// mas\n//\n// Copyright © 2026 mas-cli. All rights reserved.\n//\n\ninternal import ArgumentParser\n\nextension MAS {\n\t/// Gets & installs free apps from the App Store.\n\tstruct Get: AsyncParsableCommand {\n\t\tstatic let configuration = CommandConfiguration(\n\t\t\tabstract: \"Get & install free apps from the App Store\",\n\t\t\tdiscussion: requiresRootPrivilegesMessage(),\n\t\t\taliases: [\"purchase\"],\n\t\t)\n\n\t\t@OptionGroup\n\t\tprivate var forceOptionGroup: ForceOptionGroup\n\t\t@OptionGroup\n\t\tprivate var catalogAppIDsOptionGroup: CatalogAppIDsOptionGroup\n\n\t\tfunc run() async throws {\n\t\t\ttry await AppStore.get.apps(\n\t\t\t\twithAppIDs: catalogAppIDsOptionGroup.appIDs,\n\t\t\t\tforce: forceOptionGroup.force,\n\t\t\t\tinstalledApps: try await installedApps,\n\t\t\t\tlookupAppFromAppID: lookup(appID:),\n\t\t\t)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Commands/Home.swift",
    "content": "//\n// Home.swift\n// mas\n//\n// Copyright © 2018 mas-cli. All rights reserved.\n//\n\ninternal import ArgumentParser\nprivate import Foundation\n\nextension MAS {\n\t/// Opens App Store app pages in the default web browser.\n\t///\n\t/// Uses the iTunes Lookup API:\n\t///\n\t/// https://performance-partners.apple.com/search-api\n\tstruct Home: AsyncParsableCommand {\n\t\tstatic let configuration = CommandConfiguration(\n\t\t\tabstract: \"Open App Store app pages in the default web browser\",\n\t\t)\n\n\t\t@OptionGroup\n\t\tprivate var catalogAppIDsOptionGroup: CatalogAppIDsOptionGroup\n\n\t\tfunc run() async {\n\t\t\tawait run(lookupAppFromAppID: lookup(appID:))\n\t\t}\n\n\t\tprivate func run(lookupAppFromAppID: @escaping @Sendable (AppID) async throws -> CatalogApp) async {\n\t\t\tawait run(catalogApps: await catalogAppIDsOptionGroup.appIDs.lookupCatalogApps(using: lookupAppFromAppID))\n\t\t}\n\n\t\tfunc run(catalogApps: [CatalogApp]) async { // swiftformat:disable:this organizeDeclarations\n\t\t\tawait run(appStorePageURLStrings: catalogApps.map(\\.appStorePageURLString))\n\t\t}\n\n\t\tprivate func run(appStorePageURLStrings: [String]) async { // swiftformat:disable:this organizeDeclarations\n\t\t\tawait appStorePageURLStrings.forEach(attemptTo: \"open\") { appStorePageURLString in\n\t\t\t\tguard let url = URL(string: appStorePageURLString) else {\n\t\t\t\t\tthrow MASError.unparsableURL(appStorePageURLString)\n\t\t\t\t}\n\n\t\t\t\ttry await url.open()\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Commands/Install.swift",
    "content": "//\n// Install.swift\n// mas\n//\n// Copyright © 2015 mas-cli. All rights reserved.\n//\n\ninternal import ArgumentParser\n\nextension MAS {\n\t/// Installs previously gotten apps from the App Store.\n\tstruct Install: AsyncParsableCommand {\n\t\tstatic let configuration = CommandConfiguration(\n\t\t\tabstract: \"Install previously gotten apps from the App Store\",\n\t\t\tdiscussion: requiresRootPrivilegesMessage(),\n\t\t)\n\n\t\t@OptionGroup\n\t\tprivate var forceOptionGroup: ForceOptionGroup\n\t\t@OptionGroup\n\t\tprivate var catalogAppIDsOptionGroup: CatalogAppIDsOptionGroup\n\n\t\tfunc run() async throws {\n\t\t\ttry await AppStore.install.apps(\n\t\t\t\twithAppIDs: catalogAppIDsOptionGroup.appIDs,\n\t\t\t\tforce: forceOptionGroup.force,\n\t\t\t\tinstalledApps: try await installedApps,\n\t\t\t\tlookupAppFromAppID: lookup(appID:),\n\t\t\t)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Commands/List.swift",
    "content": "//\n// List.swift\n// mas\n//\n// Copyright © 2015 mas-cli. All rights reserved.\n//\n\ninternal import ArgumentParser\nprivate import Foundation\n\nextension MAS {\n\t/// Lists all apps installed from the App Store.\n\tstruct List: AsyncParsableCommand {\n\t\tstatic let configuration = CommandConfiguration(\n\t\t\tabstract: \"List apps installed from the App Store\",\n\t\t)\n\n\t\t@OptionGroup\n\t\tprivate var installedAppIDsOptionGroup: InstalledAppIDsOptionGroup\n\n\t\tfunc run() async throws {\n\t\t\trun(installedApps: try await installedApps)\n\t\t}\n\n\t\tfunc run(installedApps: [InstalledApp]) {\n\t\t\tlet installedApps = installedApps.filter(for: installedAppIDsOptionGroup.appIDs)\n\t\t\tguard\n\t\t\t\tlet maxADAMIDLength = installedApps.map({ String(describing: $0.adamID).count }).max(),\n\t\t\t\tlet maxNameLength = installedApps.map(\\.name.count).max()\n\t\t\telse {\n\t\t\t\tprinter.warning(\n\t\t\t\t\t\"\"\"\n\t\t\t\t\tNo installed apps found\n\n\t\t\t\t\tIf this is unexpected, any of the following command lines should fix things by reindexing apps in Spotlight\\\n\t\t\t\t\t (which might take some time):\n\n\t\t\t\t\t# Individual apps (if you know exactly what apps were incorrectly omitted):\n\t\t\t\t\tmdimport /Applications/Example.app\n\n\t\t\t\t\t# All apps (<LargeAppVolume> is the volume optionally selected for large apps):\n\t\t\t\t\tmdimport /Applications /Volumes/<LargeAppVolume>/Applications\n\n\t\t\t\t\t# All file system volumes (if neither aforementioned command solved the issue):\n\t\t\t\t\tsudo mdutil -Eai on\n\t\t\t\t\t\"\"\",\n\t\t\t\t)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tlet format = \"%\\(maxADAMIDLength)lu  %@  (%@)\"\n\t\t\tprinter.info(\n\t\t\t\tinstalledApps.map { installedApp in\n\t\t\t\t\tString(\n\t\t\t\t\t\tformat: format,\n\t\t\t\t\t\tinstalledApp.adamID,\n\t\t\t\t\t\tinstalledApp.name.padding(toLength: maxNameLength, withPad: \" \", startingAt: 0),\n\t\t\t\t\t\tinstalledApp.version,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\t.joined(separator: \"\\n\"),\n\t\t\t)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Commands/Lookup.swift",
    "content": "//\n// Lookup.swift\n// mas\n//\n// Copyright © 2016 mas-cli. All rights reserved.\n//\n\ninternal import ArgumentParser\nprivate import Foundation\n\nextension MAS {\n\t/// Outputs app information from the App Store.\n\t///\n\t/// Uses the iTunes Lookup API:\n\t///\n\t/// https://performance-partners.apple.com/search-api\n\tstruct Lookup: AsyncParsableCommand {\n\t\tstatic let configuration = CommandConfiguration(\n\t\t\tabstract: \"Output app information from the App Store\",\n\t\t\taliases: [\"info\"],\n\t\t)\n\n\t\t@OptionGroup\n\t\tprivate var catalogAppIDsOptionGroup: CatalogAppIDsOptionGroup\n\n\t\tfunc run() async {\n\t\t\tawait run(lookupAppFromAppID: lookup(appID:))\n\t\t}\n\n\t\tprivate func run(lookupAppFromAppID: @escaping @Sendable (AppID) async throws -> CatalogApp) async {\n\t\t\trun(catalogApps: await catalogAppIDsOptionGroup.appIDs.lookupCatalogApps(using: lookupAppFromAppID))\n\t\t}\n\n\t\tfunc run(catalogApps: [CatalogApp]) { // swiftformat:disable:this organizeDeclarations\n\t\t\tprinter.info(\n\t\t\t\tcatalogApps.map { catalogApp in\n\t\t\t\t\t\"\"\"\n\t\t\t\t\t\\(catalogApp.name) \\(catalogApp.version) [\\(catalogApp.displayPrice)]\n\t\t\t\t\tBy: \\(catalogApp.sellerName)\n\t\t\t\t\tReleased: \\(catalogApp.releaseDate.isoCalendarDate)\n\t\t\t\t\tMinimum OS: \\(catalogApp.minimumOSVersion)\n\t\t\t\t\tSize: \\(catalogApp.fileSizeBytes.humanReadableSize)\n\t\t\t\t\tFrom: \\(catalogApp.appStorePageURLString)\n\n\t\t\t\t\t\"\"\"\n\t\t\t\t}\n\t\t\t\t.joined(separator: \"\\n\"),\n\t\t\t\tterminator: \"\",\n\t\t\t)\n\t\t}\n\t}\n}\n\nprivate extension String {\n\tvar humanReadableSize: Self {\n\t\tInt64(self).map { $0.formatted(.byteCount(style: .file, allowedUnits: .mb, spellsOutZero: false)) } ?? self\n\t}\n\n\tvar isoCalendarDate: Self {\n\t\t(try? Date(self, strategy: .iso8601).formatted(Date.ISO8601FormatStyle(timeZone: .current).year().month().day()))\n\t\t?? self // swiftformat:disable:this indent\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Commands/Lucky.swift",
    "content": "//\n// Lucky.swift\n// mas\n//\n// Copyright © 2017 mas-cli. All rights reserved.\n//\n\ninternal import ArgumentParser\n\nextension MAS {\n\t/// Installs the first app returned from searching the App Store (app must\n\t/// have been previously gotten).\n\t///\n\t/// Uses the iTunes Search API:\n\t///\n\t/// https://performance-partners.apple.com/search-api\n\tstruct Lucky: AsyncParsableCommand {\n\t\tstatic let configuration = CommandConfiguration(\n\t\t\tabstract: \"Install the first app returned from searching the App Store\",\n\t\t\tdiscussion: // swiftformat:disable:next indent\n\t\t\t\t\"App will install only if it has already been gotten\\n\\n\\(requiresRootPrivilegesMessage(to: \"install\"))\",\n\t\t)\n\n\t\t@OptionGroup\n\t\tprivate var forceOptionGroup: ForceOptionGroup\n\t\t@OptionGroup\n\t\tprivate var searchTermOptionGroup: SearchTermOptionGroup\n\n\t\tfunc run() async throws {\n\t\t\ttry await run(installedApps: try await installedApps, searchForAppsMatchingSearchTerm: search(for:))\n\t\t}\n\n\t\tprivate func run(\n\t\t\tinstalledApps: [InstalledApp],\n\t\t\tsearchForAppsMatchingSearchTerm: (String) async throws -> [CatalogApp],\n\t\t) async throws {\n\t\t\tlet searchTerm = searchTermOptionGroup.searchTerm\n\t\t\tguard let adamID = try await searchForAppsMatchingSearchTerm(searchTerm).first?.adamID else {\n\t\t\t\tthrow MASError.noCatalogAppsFound(for: searchTerm)\n\t\t\t}\n\n\t\t\ttry await run(installedApps: installedApps, adamID: adamID)\n\t\t}\n\n\t\tprivate func run(installedApps: [InstalledApp], adamID: ADAMID) async throws {\n\t\t\ttry await AppStore.install.apps(\n\t\t\t\twithADAMIDs: [adamID],\n\t\t\t\tforce: forceOptionGroup.force,\n\t\t\t\tinstalledApps: installedApps,\n\t\t\t)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Commands/MAS.swift",
    "content": "//\n// MAS.swift\n// mas\n//\n// Copyright © 2021 mas-cli. All rights reserved.\n//\n\ninternal import ArgumentParser\ninternal import Foundation\n\n@main\nstruct MAS: AsyncParsableCommand {\n\tstatic let configuration = CommandConfiguration(\n\t\tabstract: \"Mac App Store command-line interface\",\n\t\tversion: Self.version,\n\t\tsubcommands: [\n\t\t\tConfig.self,\n\t\t\tGet.self,\n\t\t\tHome.self,\n\t\t\tInstall.self,\n\t\t\tList.self,\n\t\t\tLookup.self,\n\t\t\tLucky.self,\n\t\t\tOpen.self,\n\t\t\tOutdated.self,\n\t\t\tReset.self,\n\t\t\tSearch.self,\n\t\t\tSeller.self,\n\t\t\tSignOut.self,\n\t\t\tUninstall.self,\n\t\t\tUpdate.self,\n\t\t\tVersion.self,\n\t\t],\n\t)\n\n\tstatic let printer = Printer()\n\n\tstatic var _errorPrefix: String { // swiftlint:disable:this identifier_name\n\t\t\"\\(errorPrefix.formatted(with: errorFormat, for: FileHandle.standardError)) \"\n\t}\n\n\tprivate static func main() async { // swiftlint:disable:this unused_declaration\n\t\tawait main(nil)\n\t}\n\n\tprivate static func main(_ arguments: [String]?) async { // swiftlint:disable:this discouraged_optional_collection\n\t\tdo {\n\t\t\tlet command = try parseAsRoot(arguments)\n\t\t\tif let command = cast(command, as: (any AsyncParsableCommand & Sendable).self) {\n\t\t\t\ttry await main(command)\n\t\t\t} else {\n\t\t\t\ttry main(command)\n\t\t\t}\n\n\t\t\tlet errorCount = printer.errorCount\n\t\t\tif errorCount > 0 {\n\t\t\t\tthrow ExitCode(errorCount >= UInt64(Int32.max) ? .max : .init(errorCount))\n\t\t\t}\n\t\t} catch {\n\t\t\texit(withError: error)\n\t\t}\n\t}\n}\n\nextension MAS {\n\tstatic func main(_ command: some ParsableCommand) throws {\n\t\ttry main(command) { command in\n\t\t\tvar command = command\n\t\t\ttry command.run()\n\t\t}\n\t}\n\n\tstatic func main(_ command: some AsyncParsableCommand & Sendable) async throws {\n\t\ttry await main(command) { command in\n\t\t\tvar command = command\n\t\t\ttry await command.run()\n\t\t}\n\t}\n\n\tstatic func main<Command: ParsableCommand>(_ command: Command, _ body: (Command) throws -> Void) throws {\n\t\tdo {\n\t\t\ttry ProcessInfo.processInfo.runAsSudoEffectiveUserAndSudoEffectiveGroupIfRootEffectiveUser {\n\t\t\t\ttry body(command)\n\t\t\t}\n\t\t} catch {\n\t\t\tprinter.error(error: try error.failure)\n\t\t}\n\t}\n\n\tstatic func main<Command: AsyncParsableCommand>(_ command: Command, _ body: (Command) async throws -> Void)\n\tasync throws { // swiftformat:disable:this indent\n\t\tdo {\n\t\t\ttry await ProcessInfo.processInfo.runAsSudoEffectiveUserAndSudoEffectiveGroupIfRootEffectiveUser {\n\t\t\t\ttry await body(command)\n\t\t\t}\n\t\t} catch {\n\t\t\tprinter.error(error: try error.failure)\n\t\t}\n\t}\n}\n\nprivate extension Error {\n\tvar failure: Self {\n\t\tget throws {\n\t\t\tguard !MAS.exitCode(for: self).isSuccess else {\n\t\t\t\tthrow self\n\t\t\t}\n\n\t\t\treturn self\n\t\t}\n\t}\n}\n\nextension ParsableCommand {\n\tstatic func requiresRootPrivilegesMessage(to action: String = String(describing: Self.self).lowercased()) -> String {\n\t\t\"Requires root privileges to \\(action) apps\"\n\t}\n}\n\nprivate func cast<T>(_ instance: Any, as _: T.Type) -> T? {\n\tinstance as? T\n}\n\nprivate let applicationsFolderPath = \"/Applications\"\nprivate let applicationsFolderURL = URL(filePath: applicationsFolderPath, directoryHint: .isDirectory)\n\nlet applicationsFolderURLs = UserDefaults(suiteName: \"com.apple.appstored\")?\n.dictionary(forKey: \"PreferredVolume\")?[\"name\"] // swiftformat:disable indent\n.map { [applicationsFolderURL, URL(filePath: \"/Volumes/\\($0)\\(applicationsFolderPath)\", directoryHint: .isDirectory)] }\n?? [applicationsFolderURL]\n// swiftformat:enable indent\n"
  },
  {
    "path": "Sources/mas/Commands/Open.swift",
    "content": "//\n// Open.swift\n// mas\n//\n// Copyright © 2018 mas-cli. All rights reserved.\n//\n\nprivate import AppKit\ninternal import ArgumentParser\nprivate import Foundation\nprivate import ObjectiveC\n\nextension MAS {\n\t/// Opens app page in 'App Store.app'.\n\t///\n\t/// Uses the iTunes Lookup API:\n\t///\n\t/// https://performance-partners.apple.com/search-api\n\tstruct Open: AsyncParsableCommand {\n\t\tstatic let configuration = CommandConfiguration(\n\t\t\tabstract: \"Open app page in 'App Store.app'\",\n\t\t)\n\n\t\t@OptionGroup\n\t\tprivate var forceBundleIDOptionGroup: ForceBundleIDOptionGroup\n\t\t@Argument(help: .init(\"App ID\", valueName: \"app-id\"))\n\t\tprivate var appIDString: String?\n\n\t\tfunc run() async throws {\n\t\t\ttry await run(lookupAppFromAppID: lookup(appID:))\n\t\t}\n\n\t\tprivate func run(lookupAppFromAppID: (AppID) async throws -> CatalogApp) async throws {\n\t\t\ttry await run(appStorePageURLString: appStorePageURLString(lookupAppFromAppID: lookupAppFromAppID))\n\t\t}\n\n\t\tprivate func run(appStorePageURLString: String?) async throws {\n\t\t\tguard let appStorePageURLString else {\n\t\t\t\t// If no App Store Page URL was given, just open the MAS GUI app\n\t\t\t\ttry await openMacAppStore()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\ttry await openMacAppStorePage(forAppStorePageURLString: appStorePageURLString)\n\t\t}\n\n\t\tprivate func appStorePageURLString(lookupAppFromAppID: (AppID) async throws -> CatalogApp) async throws -> String? {\n\t\t\tguard let appIDString else {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn try await lookupAppFromAppID(\n\t\t\t\tAppID(from: appIDString, forceBundleID: forceBundleIDOptionGroup.forceBundleID),\n\t\t\t)\n\t\t\t.appStorePageURLString\n\t\t}\n\t}\n}\n\nprivate func openMacAppStore() async throws {\n\tguard let macAppStoreSchemeURL = URL(string: \"macappstore:\") else {\n\t\tthrow MASError.error(\"Failed to create URL from macappstore scheme\")\n\t}\n\n\tlet workspace = NSWorkspace.shared\n\tguard let appURL = workspace.urlForApplication(toOpen: macAppStoreSchemeURL) else {\n\t\tthrow MASError.error(\"Failed to find app to open macappstore URLs\")\n\t}\n\n\ttry await workspace.openApplication(at: appURL, configuration: .init())\n}\n\nprivate func openMacAppStorePage(forAppStorePageURLString appStorePageURLString: String) async throws {\n\tguard var urlComponents = URLComponents(string: appStorePageURLString) else {\n\t\tthrow MASError.unparsableURL(appStorePageURLString)\n\t}\n\n\turlComponents.scheme = masScheme\n\tguard let url = urlComponents.url else {\n\t\tthrow MASError.unparsableURL(String(describing: urlComponents))\n\t}\n\n\ttry await url.open()\n}\n\nprivate let masScheme = \"macappstore\"\n"
  },
  {
    "path": "Sources/mas/Commands/OptionGroups/CatalogAppIDsOptionGroup.swift",
    "content": "//\n// CatalogAppIDsOptionGroup.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\ninternal import ArgumentParser\n\nstruct CatalogAppIDsOptionGroup: ParsableArguments {\n\t@OptionGroup\n\tprivate var forceBundleIDOptionGroup: ForceBundleIDOptionGroup\n\t@Argument(help: .init(\"App ID\", valueName: \"app-id\"))\n\tprivate var appIDStrings: [String]\n\n\tvar appIDs: [AppID] {\n\t\tappIDStrings.map { .init(from: $0, forceBundleID: forceBundleIDOptionGroup.forceBundleID) }\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Commands/OptionGroups/ForceBundleIDOptionGroup.swift",
    "content": "//\n// ForceBundleIDOptionGroup.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\nprivate import ArgumentParser\n\nstruct ForceBundleIDOptionGroup: ParsableArguments {\n\t@Flag(name: .customLong(\"bundle\"), help: \"Process all app IDs as bundle IDs\")\n\tvar forceBundleID = false\n}\n"
  },
  {
    "path": "Sources/mas/Commands/OptionGroups/ForceOptionGroup.swift",
    "content": "//\n// ForceOptionGroup.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\nprivate import ArgumentParser\n\nstruct ForceOptionGroup: ParsableArguments {\n\t@Flag(help: \"Force reinstall\")\n\tvar force = false\n}\n"
  },
  {
    "path": "Sources/mas/Commands/OptionGroups/InstalledAppIDsOptionGroup.swift",
    "content": "//\n// InstalledAppIDsOptionGroup.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\ninternal import ArgumentParser\n\nstruct InstalledAppIDsOptionGroup: ParsableArguments {\n\t@OptionGroup\n\tprivate var forceBundleIDOptionGroup: ForceBundleIDOptionGroup\n\t@Argument(help: .init(\"App ID\", valueName: \"app-id\"))\n\tprivate var appIDStrings = [String]()\n\n\tvar appIDs: [AppID] {\n\t\tappIDStrings.map { .init(from: $0, forceBundleID: forceBundleIDOptionGroup.forceBundleID) }\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Commands/OptionGroups/OutdatedAccuracy.swift",
    "content": "//\n// OutdatedAccuracy.swift\n// mas\n//\n// Copyright © 2026 mas-cli. All rights reserved.\n//\n\ninternal import ArgumentParser\n\nenum OutdatedAccuracy: String, EnumerableFlag {\n\tcase accurate\n\tcase inaccurate\n\n\tstatic func help(for outdatedAccuracy: Self) -> ArgumentHelp? {\n\t\tswitch outdatedAccuracy {\n\t\tcase .accurate:\n\t\t\t\"\"\"\n\t\t\tUse accurate, slower logic that starts then cancels a download for each queried app, which can exceed download\\\n\t\t\t limits & which will open dialogs for undownloadable apps\n\t\t\t\"\"\"\n\t\tcase .inaccurate:\n\t\t\t\"Use inaccurate, faster logic that avoids dialogs\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Commands/OptionGroups/OutdatedAppOptionGroup.swift",
    "content": "//\n// OutdatedAppOptionGroup.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\nprivate import ArgumentParser\n\nstruct OutdatedAppOptionGroup: ParsableArguments {\n\t@Flag\n\tvar accuracy = OutdatedAccuracy.inaccurate\n\t@Flag(\n\t\tname: .customLong(\"check-min-os\"),\n\t\tinversion: .prefixedNo,\n\t\thelp: \"Check that macOS is new enough to install the latest app version\",\n\t)\n\tvar shouldCheckMinimumOSVersion = true\n}\n"
  },
  {
    "path": "Sources/mas/Commands/OptionGroups/SearchTermOptionGroup.swift",
    "content": "//\n// SearchTermOptionGroup.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\ninternal import ArgumentParser\n\nstruct SearchTermOptionGroup: ParsableArguments {\n\t@Argument(help: .init(\"Search terms are concatenated into a single search\", valueName: \"search-term\"))\n\tprivate var searchTermElements: [String]\n\n\tvar searchTerm: String {\n\t\tsearchTermElements.joined(separator: \" \")\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Commands/OptionGroups/VerboseOptionGroup.swift",
    "content": "//\n// VerboseOptionGroup.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\nprivate import ArgumentParser\n\nstruct VerboseOptionGroup: ParsableArguments {\n\t@Flag(help: \"Output warnings about app IDs unknown to the App Store\")\n\tvar verbose = false\n}\n"
  },
  {
    "path": "Sources/mas/Commands/Outdated.swift",
    "content": "//\n// Outdated.swift\n// mas\n//\n// Copyright © 2015 mas-cli. All rights reserved.\n//\n\ninternal import ArgumentParser\nprivate import Foundation\n\nextension MAS {\n\t/// Outputs a list of installed apps which have updates available to be\n\t/// installed from the App Store.\n\tstruct Outdated: AsyncParsableCommand {\n\t\tstatic let configuration = CommandConfiguration(\n\t\t\tabstract: \"List pending app updates from the App Store\",\n\t\t)\n\n\t\t@OptionGroup\n\t\tprivate var outdatedAppOptionGroup: OutdatedAppOptionGroup\n\t\t@OptionGroup\n\t\tprivate var verboseOptionGroup: VerboseOptionGroup\n\t\t@OptionGroup\n\t\tprivate var installedAppIDsOptionGroup: InstalledAppIDsOptionGroup\n\n\t\tfunc run() async throws {\n\t\t\tawait run(installedApps: try await installedApps.filter(!\\.isTestFlight), lookupAppFromAppID: lookup(appID:))\n\t\t}\n\n\t\tprivate func run(\n\t\t\tinstalledApps: [InstalledApp],\n\t\t\tlookupAppFromAppID: @escaping @Sendable (AppID) async throws -> CatalogApp,\n\t\t) async {\n\t\t\trun(\n\t\t\t\toutdatedApps: await installedApps.outdatedApps(\n\t\t\t\t\tfilterFor: installedAppIDsOptionGroup.appIDs,\n\t\t\t\t\tlookupAppFromAppID: lookupAppFromAppID,\n\t\t\t\t\taccuracy: outdatedAppOptionGroup.accuracy,\n\t\t\t\t\tshouldCheckMinimumOSVersion: outdatedAppOptionGroup.shouldCheckMinimumOSVersion,\n\t\t\t\t\tshouldWarnIfUnknownApp: verboseOptionGroup.verbose,\n\t\t\t\t),\n\t\t\t)\n\t\t}\n\n\t\tprivate func run(outdatedApps: [OutdatedApp]) {\n\t\t\tguard\n\t\t\t\tlet maxADAMIDLength = outdatedApps.map({ String(describing: $0.installedApp.adamID).count }).max(),\n\t\t\t\tlet maxNameLength = outdatedApps.map(\\.installedApp.name.count).max(),\n\t\t\t\tlet maxVersionLength = outdatedApps.map(\\.installedApp.version.count).max()\n\t\t\telse {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tlet format = \"%\\(maxADAMIDLength)lu  %@  (%@ -> %@)\"\n\t\t\tprinter.info(\n\t\t\t\toutdatedApps.map { installedApp, newVersion in\n\t\t\t\t\tString(\n\t\t\t\t\t\tformat: format,\n\t\t\t\t\t\tinstalledApp.adamID,\n\t\t\t\t\t\tinstalledApp.name.padding(toLength: maxNameLength, withPad: \" \", startingAt: 0),\n\t\t\t\t\t\tinstalledApp.version.padding(toLength: maxVersionLength, withPad: \" \", startingAt: 0),\n\t\t\t\t\t\tnewVersion,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\t.joined(separator: \"\\n\"),\n\t\t\t)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Commands/Reset.swift",
    "content": "//\n// Reset.swift\n// mas\n//\n// Copyright © 2016 mas-cli. All rights reserved.\n//\n\nprivate import AppKit\ninternal import ArgumentParser\nprivate import CommerceKit\nprivate import Darwin\nprivate import Foundation\n\nextension MAS {\n\t/// Mimics the \"Reset Application\" command in the App Store debug menu, which\n\t/// performs the following steps:\n\t///\n\t/// - `killall Dock`\n\t/// - `killall storeagent` (`storeagent` no longer exists)\n\t/// - deletes the `com.apple.appstore` download folder\n\t/// - clears cookies (appears to be a no-op)\n\t///\n\t/// As `storeagent` no longer exists, terminates all processes known to be\n\t/// associated with the App Store.\n\tstruct Reset: ParsableCommand {\n\t\tstatic let configuration = CommandConfiguration(\n\t\t\tabstract: \"Reset App Store processes & clear cached App Store downloads\",\n\t\t)\n\n\t\tfunc run() {\n\t\t\tfor bundleID in [\"com.apple.dock\", \"com.apple.storeuid\"] {\n\t\t\t\tfor app in NSRunningApplication.runningApplications(withBundleIdentifier: bundleID) where !app.terminate() {\n\t\t\t\t\tprinter.warning(\"Failed to terminate app with bundle ID:\", bundleID)\n\t\t\t\t\tif !app.forceTerminate() {\n\t\t\t\t\t\tprinter.error(\"Failed to force terminate app with bundle ID:\", bundleID)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet executablePathSet = Set([\n\t\t\t\t\"/System/Library/Frameworks/StoreKit.framework/Support/storekitagent\",\n\t\t\t\t\"/System/Library/PrivateFrameworks/AppStoreComponents.framework/Support/appstorecomponentsd\",\n\t\t\t\t\"/System/Library/PrivateFrameworks/AppStoreDaemon.framework/Support/appstoreagent\",\n\t\t\t\t\"\"\"\n\t\t\t\t/System/Library/PrivateFrameworks/CascadeSets.framework/Versions/A/XPCServices/SetStoreUpdateService.xpc/Contents/MacOS/SetStoreUpdateService\n\t\t\t\t\"\"\",\n\t\t\t\t\"/System/Library/PrivateFrameworks/CommerceKit.framework/Versions/A/Resources/storeaccountd\",\n\t\t\t\t\"/System/Library/PrivateFrameworks/CommerceKit.framework/Versions/A/Resources/storeassetd\",\n\t\t\t\t\"/System/Library/PrivateFrameworks/CommerceKit.framework/Versions/A/Resources/storedownloadd\",\n\t\t\t\t\"/System/Library/PrivateFrameworks/CommerceKit.framework/Versions/A/Resources/storeinstalld\",\n\t\t\t\t\"/System/Library/PrivateFrameworks/CommerceKit.framework/Versions/A/Resources/storelegacy\",\n\t\t\t])\n\n\t\t\tvar processListMIB = [CTL_KERN, KERN_PROC, KERN_PROC_ALL]\n\t\t\tvar length = 0\n\t\t\tguard unsafe sysctl(&processListMIB, u_int(processListMIB.count), nil, &length, nil, 0) == 0 else {\n\t\t\t\tprinter.error(\"Failed to get process list length\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tvar kinfoProcs = unsafe [kinfo_proc](repeating: kinfo_proc(), count: length / MemoryLayout<kinfo_proc>.stride)\n\t\t\tguard unsafe sysctl(&processListMIB, u_int(processListMIB.count), &kinfoProcs, &length, nil, 0) == 0 else {\n\t\t\t\tprinter.error(\"Failed to get process list\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tvar executablePathBuffer = [CChar](repeating: 0, count: .init(PATH_MAX))\n\t\t\tfor pid in unsafe kinfoProcs.map(\\.kp_proc.p_pid) {\n\t\t\t\tguard\n\t\t\t\t\tunsafe proc_pidpath(pid, &executablePathBuffer, UInt32(executablePathBuffer.count)) > 0,\n\t\t\t\t\tlet executablePath = String(cString: executablePathBuffer, encoding: .utf8),\n\t\t\t\t\texecutablePathSet.contains(executablePath)\n\t\t\t\telse {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tlet exitStatus = kill(pid, SIGTERM)\n\t\t\t\tif exitStatus != 0 {\n\t\t\t\t\tprinter.error(\"Failed to terminate\", executablePath, \"getting exit status\", exitStatus, \"for pid\", pid)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet folder = CKDownloadDirectory(nil)\n\t\t\tdo {\n\t\t\t\ttry FileManager.default.removeItem(atPath: folder)\n\t\t\t} catch {\n\t\t\t\tprinter.error(\"Failed to delete download folder\", folder, error: error)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Commands/Search.swift",
    "content": "//\n// Search.swift\n// mas\n//\n// Copyright © 2016 mas-cli. All rights reserved.\n//\n\ninternal import ArgumentParser\nprivate import Foundation\n\nextension MAS {\n\t/// Searches for apps in the App Store.\n\t///\n\t/// Uses the iTunes Search API:\n\t///\n\t/// https://performance-partners.apple.com/search-api\n\tstruct Search: AsyncParsableCommand {\n\t\tstatic let configuration = CommandConfiguration(\n\t\t\tabstract: \"Search for apps in the App Store\",\n\t\t)\n\n\t\t@Flag(help: \"Output the price of each app\")\n\t\tprivate var price = false\n\t\t@OptionGroup\n\t\tprivate var searchTermOptionGroup: SearchTermOptionGroup\n\n\t\tfunc run() async throws {\n\t\t\ttry await run(searchForAppsMatchingSearchTerm: search(for:))\n\t\t}\n\n\t\tprivate func run(searchForAppsMatchingSearchTerm: (String) async throws -> [CatalogApp]) async throws {\n\t\t\ttry run(catalogApps: try await searchForAppsMatchingSearchTerm(searchTermOptionGroup.searchTerm))\n\t\t}\n\n\t\tfunc run(catalogApps: [CatalogApp]) throws { // swiftformat:disable:this organizeDeclarations\n\t\t\tguard\n\t\t\t\tlet maxADAMIDLength = catalogApps.map({ String(describing: $0.adamID).count }).max(),\n\t\t\t\tlet maxNameLength = catalogApps.map(\\.name.count).max()\n\t\t\telse {\n\t\t\t\tthrow MASError.noCatalogAppsFound(for: searchTermOptionGroup.searchTerm)\n\t\t\t}\n\n\t\t\tlet format = \"%\\(maxADAMIDLength)lu  %@  (%@)\\(price ? \"  %@\" : \"\")\"\n\t\t\tprinter.info(\n\t\t\t\tcatalogApps.map { catalogApp in\n\t\t\t\t\tString(\n\t\t\t\t\t\tformat: format,\n\t\t\t\t\t\tcatalogApp.adamID,\n\t\t\t\t\t\tcatalogApp.name.padding(toLength: maxNameLength, withPad: \" \", startingAt: 0),\n\t\t\t\t\t\tcatalogApp.version,\n\t\t\t\t\t\tcatalogApp.displayPrice,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\t.joined(separator: \"\\n\"),\n\t\t\t)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Commands/Seller.swift",
    "content": "//\n// Seller.swift\n// mas\n//\n// Copyright © 2018 mas-cli. All rights reserved.\n//\n\ninternal import ArgumentParser\nprivate import Foundation\n\nextension MAS {\n\t/// Opens apps' seller pages in the default web browser.\n\t///\n\t/// Uses the iTunes Lookup API:\n\t///\n\t/// https://performance-partners.apple.com/search-api\n\tstruct Seller: AsyncParsableCommand {\n\t\tstatic let configuration = CommandConfiguration(\n\t\t\tabstract: \"Open apps' seller pages in the default web browser\",\n\t\t\taliases: [\"vendor\"],\n\t\t)\n\n\t\t@OptionGroup\n\t\tprivate var catalogAppIDsOptionGroup: CatalogAppIDsOptionGroup\n\n\t\tfunc run() async {\n\t\t\tawait run(lookupAppFromAppID: lookup(appID:))\n\t\t}\n\n\t\tprivate func run(lookupAppFromAppID: @escaping @Sendable (AppID) async throws -> CatalogApp) async {\n\t\t\tawait run(catalogApps: await catalogAppIDsOptionGroup.appIDs.lookupCatalogApps(using: lookupAppFromAppID))\n\t\t}\n\n\t\tfunc run(catalogApps: [CatalogApp]) async { // swiftformat:disable:this organizeDeclarations\n\t\t\tawait run(\n\t\t\t\tsellerURLStrings: catalogApps.compactMap { catalogApp in\n\t\t\t\t\tguard let sellerURLString = catalogApp.sellerURLString else {\n\t\t\t\t\t\tprinter.error(\"No seller website available for ADAM ID\", catalogApp.adamID)\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\n\t\t\t\t\treturn sellerURLString\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\n\t\tprivate func run(sellerURLStrings: [String]) async { // swiftformat:disable:this organizeDeclarations\n\t\t\tawait sellerURLStrings.forEach(attemptTo: \"open\") { sellerURLString in\n\t\t\t\tguard let url = URL(string: sellerURLString) else {\n\t\t\t\t\tthrow MASError.unparsableURL(sellerURLString)\n\t\t\t\t}\n\n\t\t\t\ttry await url.open()\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Commands/SignOut.swift",
    "content": "//\n// SignOut.swift\n// mas\n//\n// Copyright © 2016 mas-cli. All rights reserved.\n//\n\ninternal import ArgumentParser\nprivate import StoreFoundation\n\nextension MAS {\n\t/// Signs out of the Apple Account currently signed in to the App Store.\n\tstruct SignOut: ParsableCommand {\n\t\tstatic let configuration = CommandConfiguration(\n\t\t\tcommandName: \"signout\",\n\t\t\tabstract: \"Sign out of the App Store\",\n\t\t)\n\n\t\tfunc run() {\n\t\t\tISServiceProxy.genericShared().accountService.signOut()\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Commands/Uninstall.swift",
    "content": "//\n// Uninstall.swift\n// mas\n//\n// Copyright © 2018 mas-cli. All rights reserved.\n//\n\ninternal import ArgumentParser\nprivate import Foundation\nprivate import OrderedCollections\n\nextension MAS {\n\t/// Uninstalls apps installed from the App Store.\n\tstruct Uninstall: AsyncParsableCommand {\n\t\tstatic let configuration = CommandConfiguration(\n\t\t\tabstract: \"Uninstall apps installed from the App Store\",\n\t\t\tdiscussion: requiresRootPrivilegesMessage(),\n\t\t)\n\n\t\t/// Flag indicating that uninstall shouldn't be performed.\n\t\t@Flag(name: .customLong(\"dry-run\"), help: \"Perform dry run\")\n\t\tprivate var isPerformingDryRun = false\n\t\t@Flag(name: .customLong(\"all\"), help: \"Uninstall all App Store apps\")\n\t\tprivate var isUninstallingAll = false\n\t\t@OptionGroup\n\t\tprivate var installedAppIDsOptionGroup: InstalledAppIDsOptionGroup\n\n\t\tfunc validate() throws {\n\t\t\tif isUninstallingAll != installedAppIDsOptionGroup.appIDs.isEmpty {\n\t\t\t\tthrow ValidationError(\n\t\t\t\t\tisUninstallingAll\n\t\t\t\t\t? \"Cannot specify both --all & app IDs\" // swiftformat:disable:this indent\n\t\t\t\t\t: \"Must specify either --all or at least one app ID\",\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tfunc run() async throws {\n\t\t\ttry run(installedApps: try await installedApps)\n\t\t}\n\n\t\tprivate func run(installedApps: [InstalledApp]) throws {\n\t\t\tlet uninstallingAppPathSet = (\n\t\t\t\tisUninstallingAll ? installedApps.map { .bundleID($0.bundleID) } : installedAppIDsOptionGroup.appIDs,\n\t\t\t)\n\t\t\t.reduce(into: OrderedSet<String>()) { uninstallingAppPathSet, appID in\n\t\t\t\tlet uninstallingApps = installedApps.filter { $0.matches(appID) }\n\t\t\t\tguard !uninstallingApps.isEmpty else {\n\t\t\t\t\tprinter.error(appID.notInstalledMessage)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tuninstallingAppPathSet.append(contentsOf: uninstallingApps.map(\\.path))\n\t\t\t}\n\t\t\tguard !uninstallingAppPathSet.isEmpty else {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tguard !isPerformingDryRun else {\n\t\t\t\tprinter.notice(\"Dry run. A wet run would uninstall:\\n\")\n\t\t\t\tfor uninstallingAppPath in uninstallingAppPathSet {\n\t\t\t\t\tprinter.info(uninstallingAppPath)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tguard getuid() == 0 else {\n\t\t\t\ttry sudo(MAS._commandName, args: CommandLine.arguments.dropFirst())\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tlet processInfo = ProcessInfo.processInfo\n\t\t\tlet uid = try processInfo.sudoUID\n\t\t\tlet gid = try processInfo.sudoGID\n\t\t\tlet fileManager = FileManager.default\n\t\t\tfor appPath in uninstallingAppPathSet {\n\t\t\t\tlet attributes = try fileManager.attributesOfItem(atPath: appPath)\n\t\t\t\tguard let appUID = attributes[.ownerAccountID] as? uid_t else {\n\t\t\t\t\tprinter.error(\"Failed to get uid of\", appPath)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tguard let appGID = attributes[.groupOwnerAccountID] as? gid_t else {\n\t\t\t\t\tprinter.error(\"Failed to get gid of\", appPath)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tdo {\n\t\t\t\t\ttry mas.run(asEffectiveUID: 0, andEffectiveGID: 0) {\n\t\t\t\t\t\ttry fileManager.setAttributes([.ownerAccountID: uid, .groupOwnerAccountID: gid], ofItemAtPath: appPath)\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\tprinter.error(\"Failed to change ownership of\", appPath.quoted, \"to uid\", uid, \"& gid\", gid, error: error)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tvar chownPath = appPath\n\t\t\t\tdefer {\n\t\t\t\t\tdo {\n\t\t\t\t\t\ttry mas.run(asEffectiveUID: 0, andEffectiveGID: 0) {\n\t\t\t\t\t\t\ttry fileManager.setAttributes(\n\t\t\t\t\t\t\t\t[.ownerAccountID: appUID, .groupOwnerAccountID: appGID],\n\t\t\t\t\t\t\t\tofItemAtPath: chownPath,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tprinter.warning(\n\t\t\t\t\t\t\t\"Failed to revert ownership of\",\n\t\t\t\t\t\t\tchownPath.quoted,\n\t\t\t\t\t\t\t\"back to uid\",\n\t\t\t\t\t\t\tappUID,\n\t\t\t\t\t\t\t\"& gid\",\n\t\t\t\t\t\t\tappGID,\n\t\t\t\t\t\t\terror: error,\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvar uninstalledAppNSURL = NSURL?.none // swiftlint:disable:this legacy_objc_type\n\t\t\t\ttry unsafe fileManager.trashItem(\n\t\t\t\t\tat: .init(filePath: appPath, directoryHint: .isDirectory),\n\t\t\t\t\tresultingItemURL: &uninstalledAppNSURL,\n\t\t\t\t)\n\t\t\t\tguard let uninstalledAppPath = uninstalledAppNSURL?.path else {\n\t\t\t\t\tprinter.error(\n\t\t\t\t\t\t\"\"\"\n\t\t\t\t\t\tFailed to revert ownership of uninstalled \\(appPath.quoted) back to uid \\(appUID) & gid \\(appGID):\\\n\t\t\t\t\t\t failed to obtain uninstalled app URL\n\t\t\t\t\t\t\"\"\",\n\t\t\t\t\t)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tchownPath = uninstalledAppPath\n\t\t\t\tprinter.info(\"Uninstalled\", appPath.quoted, \"to\", chownPath.quoted)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Commands/Update.swift",
    "content": "//\n// Update.swift\n// mas\n//\n// Copyright © 2015 mas-cli. All rights reserved.\n//\n\ninternal import ArgumentParser\nprivate import StoreFoundation\n\nextension MAS {\n\t/// Updates outdated apps installed from the App Store.\n\tstruct Update: AsyncParsableCommand {\n\t\tstatic let configuration = CommandConfiguration(\n\t\t\tabstract: \"Update outdated apps installed from the App Store\",\n\t\t\tdiscussion: requiresRootPrivilegesMessage(),\n\t\t\taliases: [\"upgrade\"],\n\t\t)\n\n\t\t@OptionGroup\n\t\tprivate var outdatedAppOptionGroup: OutdatedAppOptionGroup\n\t\t@OptionGroup\n\t\tprivate var forceOptionGroup: ForceOptionGroup\n\t\t@OptionGroup\n\t\tprivate var verboseOptionGroup: VerboseOptionGroup\n\t\t@OptionGroup\n\t\tprivate var installedAppIDsOptionGroup: InstalledAppIDsOptionGroup\n\n\t\tfunc run() async throws {\n\t\t\ttry await run(installedApps: try await installedApps.filter(!\\.isTestFlight), lookupAppFromAppID: lookup(appID:))\n\t\t}\n\n\t\tprivate func run(\n\t\t\tinstalledApps: [InstalledApp],\n\t\t\tlookupAppFromAppID: @escaping @Sendable (AppID) async throws -> CatalogApp,\n\t\t) async throws {\n\t\t\ttry await run(\n\t\t\t\toutdatedApps: forceOptionGroup.force // swiftformat:disable:next indent\n\t\t\t\t? installedApps.filter(for: installedAppIDsOptionGroup.appIDs).map { ($0, \"\") }\n\t\t\t\t: await installedApps.outdatedApps(\n\t\t\t\t\tfilterFor: installedAppIDsOptionGroup.appIDs,\n\t\t\t\t\tlookupAppFromAppID: lookupAppFromAppID,\n\t\t\t\t\taccuracy: outdatedAppOptionGroup.accuracy,\n\t\t\t\t\tshouldCheckMinimumOSVersion: outdatedAppOptionGroup.shouldCheckMinimumOSVersion,\n\t\t\t\t\tshouldWarnIfUnknownApp: verboseOptionGroup.verbose,\n\t\t\t\t),\n\t\t\t)\n\t\t}\n\n\t\tprivate func run(outdatedApps: [OutdatedApp]) async throws {\n\t\t\ttry await AppStore.update.apps(withADAMIDs: outdatedApps.map(\\.installedApp.adamID))\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Commands/Version.swift",
    "content": "//\n// Version.swift\n// mas\n//\n// Copyright © 2015 mas-cli. All rights reserved.\n//\n\ninternal import ArgumentParser\n\nextension MAS {\n\t/// Outputs the version of mas.\n\tstruct Version: ParsableCommand {\n\t\tstatic let configuration = CommandConfiguration(\n\t\t\tabstract: \"Output version number\",\n\t\t)\n\n\t\tfunc run() {\n\t\t\tprinter.info(version)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Controllers/CatalogApp+ITunesSearch.swift",
    "content": "//\n// CatalogApp+ITunesSearch.swift\n// mas\n//\n// Copyright © 2018 mas-cli. All rights reserved.\n//\n\ninternal import Foundation\nprivate import Sextant\nprivate import SwiftSoup\n\nfunc lookup(appID: AppID) async throws -> CatalogApp {\n\ttry await lookup(appID: appID, inRegion: appStoreRegion)\n}\n\n/// Look up app details from the App Store catalog via the iTunes Search API.\n///\n/// https://performance-partners.apple.com/search-api\n///\n/// - Parameters:\n///   - appID: App ID.\n///   - region: The ISO 3166-1 alpha-2 region of the storefront in which to\n///     lookup apps.\n/// - Returns: A `CatalogApp` for the given `appID` if `appID` is valid.\n/// - Throws: A `MASError.unknownAppID(appID)` if `appID` is invalid.\n///   Some other `Error` if any other problem occurs.\nfunc lookup(\n\tappID: AppID,\n\tinRegion region: Region = appStoreRegion,\n\tdataFrom dataSource: (URL) async throws -> (Data, URLResponse) = urlSession.data(from:),\n) async throws -> CatalogApp {\n\tlet queryItem =\n\t\tswitch appID {\n\t\tcase let .adamID(adamID):\n\t\t\tURLQueryItem(name: \"id\", value: .init(adamID))\n\t\tcase let .bundleID(bundleID):\n\t\t\tURLQueryItem(name: \"bundleId\", value: bundleID)\n\t\t}\n\tguard // swiftformat:disable:this wrap wrapArguments\n\t\tlet catalogApp = // swiftformat:disable:next indent\n\t\t\ttry await getCatalogApps(from: try url(\"lookup\", queryItem, inRegion: region), dataFrom: dataSource).first\n\telse {\n\t\tguard\n\t\t\tlet catalogApp = try await getCatalogApps(\n\t\t\t\tfrom: try url(\"lookup\", queryItem, inRegion: region, additionalQueryItems: []),\n\t\t\t\tdataFrom: dataSource,\n\t\t\t)\n\t\t\t.first,\n\t\t\tcatalogApp.supportedDevices?.contains(\"MacDesktop-MacDesktop\") ?? false\n\t\telse {\n\t\t\tthrow MASError.unknownAppID(appID)\n\t\t}\n\n\t\treturn catalogApp.with(minimumOSVersion: await catalogApp.minimumOSVersion(dataFrom: dataSource))\n\t}\n\n\treturn catalogApp\n}\n\nprivate extension CatalogApp {\n\tfunc minimumOSVersion(dataFrom: (URL) async throws -> (Data, URLResponse) = urlSession.data(from:)) async -> String {\n\t\tdo {\n\t\t\treturn try await URL(string: appStorePageURLString)\n\t\t\t.flatMap { url in // swiftformat:disable indent\n\t\t\t\ttry unsafe SwiftSoup.parse(try await dataFrom(url).0, appStorePageURLString)\n\t\t\t\t.select(\"#serialized-server-data\")\n\t\t\t\t.first()?\n\t\t\t\t.data()\n\t\t\t\t.query(\n\t\t\t\t\tstring:\n\t\t\t\t\t\t\"$.data[0].data.shelfMapping.information.items[?(@.title == 'Compatibility')].items[?(@.heading == 'Mac')].text\",\n\t\t\t\t)?\n\t\t\t\t.firstMatch(of: minimumOSVersionRegex)?\n\t\t\t\t.version\n\t\t\t}\n\t\t\t.map(String.init(_:)) ?? minimumOSVersion // swiftformat:enable indent\n\t\t} catch {\n\t\t\treturn minimumOSVersion\n\t\t}\n\t}\n}\n\nfunc search(for searchTerm: String) async throws -> [CatalogApp] {\n\ttry await search(for: searchTerm, inRegion: appStoreRegion)\n}\n\n/// Search for app details from the App Store catalog via the iTunes Search API.\n///\n/// https://performance-partners.apple.com/search-api\n///\n/// - Parameters:\n///   - searchTerm: Term for which to search.\n///   - region: The ISO 3166-1 alpha-2 region of the storefront in which to\n///     search for apps.\n/// - Returns: A `[CatalogApp]` matching `searchTerm`.\n/// - Throws: An `Error` if any problem occurs.\nfunc search(\n\tfor searchTerm: String,\n\tinRegion region: Region = appStoreRegion,\n\tdataFrom dataSource: @escaping @Sendable (URL) async throws -> (Data, URLResponse) = urlSession.data(from:),\n) async throws -> [CatalogApp] {\n\tlet queryItem = URLQueryItem(name: \"term\", value: searchTerm)\n\tlet catalogApps = try await getCatalogApps(from: try url(\"search\", queryItem, inRegion: region), dataFrom: dataSource)\n\tlet adamIDSet = Set(catalogApps.map(\\.adamID))\n\treturn catalogApps.priorityMerge(\n\t\ttry await getCatalogApps(\n\t\t\tfrom: try url(\"search\", queryItem, inRegion: region, additionalQueryItems: []),\n\t\t\tdataFrom: dataSource,\n\t\t)\n\t\t.filter { ($0.supportedDevices?.contains(\"MacDesktop-MacDesktop\") ?? false) && !adamIDSet.contains($0.adamID) }\n\t\t.concurrentMap { $0.with(minimumOSVersion: await $0.minimumOSVersion(dataFrom: dataSource)) },\n\t) { $0.name.similarity(to: searchTerm) }\n}\n\nprivate func url(\n\t_ action: String,\n\t_ queryItem: URLQueryItem,\n\tinRegion region: Region,\n\tadditionalQueryItems: [URLQueryItem] = [URLQueryItem(name: \"entity\", value: \"desktopSoftware\")],\n) throws -> URL {\n\tlet urlString = \"https://itunes.apple.com/\\(action)\"\n\tguard let url = URL(string: urlString) else {\n\t\tthrow MASError.unparsableURL(urlString)\n\t}\n\n\treturn url.appending(\n\t\tqueryItems: [URLQueryItem(name: \"media\", value: \"software\")]\n\t\t+ additionalQueryItems // swiftformat:disable indent\n\t\t+ [\n\t\t\tURLQueryItem(name: \"country\", value: region),\n\t\t\tqueryItem,\n\t\t],\n\t) // swiftformat:enable indent\n}\n\nprivate func getCatalogApps(from url: URL, dataFrom: (URL) async throws -> (Data, URLResponse))\nasync throws -> [CatalogApp] { // swiftformat:disable:this indent\n\tlet (data, _) = try await dataFrom(url)\n\tdo {\n\t\treturn try JSONDecoder().decode(CatalogAppResults.self, from: data).results\n\t} catch {\n\t\tthrow MASError.error(\"Failed to parse JSON from response \\(url)\", error: .init(data: data, encoding: .utf8) ?? \"\")\n\t}\n}\n\nprivate let urlSession = URLSession(configuration: .ephemeral)\nprivate nonisolated(unsafe) let minimumOSVersionRegex = /macOS\\s*(?<version>\\S+)/\n"
  },
  {
    "path": "Sources/mas/Controllers/InstalledApp+Spotlight.swift",
    "content": "//\n// InstalledApp+Spotlight.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\nprivate import Atomics\nprivate import Foundation\nprivate import ObjectiveC\n\nprivate extension URL {\n\tvar installedAppURLs: [URL] {\n\t\tFileManager.default // swiftformat:disable indent\n\t\t.enumerator(at: self, includingPropertiesForKeys: [.isDirectoryKey], options: [.skipsHiddenFiles])\n\t\t.map { enumerator in\n\t\t\tenumerator.compactMap { item in\n\t\t\t\tguard\n\t\t\t\t\tlet url = item as? URL,\n\t\t\t\t\t(try? url.resourceValues(forKeys: [.isDirectoryKey]).isDirectory) == true,\n\t\t\t\t\turl.pathExtension == \"app\"\n\t\t\t\telse {\n\t\t\t\t\treturn nil as URL?\n\t\t\t\t}\n\n\t\t\t\tenumerator.skipDescendants()\n\t\t\t\treturn try? url.appending(path: \"Contents/_MASReceipt/receipt\", directoryHint: .notDirectory)\n\t\t\t\t.resourceValues(forKeys: [.fileSizeKey])\n\t\t\t\t.fileSize\n\t\t\t\t.flatMap { $0 > 0 ? url : nil }\n\t\t\t}\n\t\t}\n\t\t?? []\n\t} // swiftformat:enable indent\n}\n\nvar installedApps: [InstalledApp] {\n\tget async throws {\n\t\ttry await mas.installedApps(matching: \"kMDItemAppStoreAdamID LIKE '*'\")\n\t}\n}\n\nfunc installedApps(withADAMID adamID: ADAMID) async throws -> [InstalledApp] {\n\ttry await installedApps(matching: \"kMDItemAppStoreAdamID = \\(adamID)\")\n}\n\n@MainActor\nfunc installedApps(matching metadataQuery: String) async throws -> [InstalledApp] {\n\tvar observer = (any NSObjectProtocol)?.none\n\tdefer {\n\t\tif let observer {\n\t\t\tNotificationCenter.default.removeObserver(observer)\n\t\t}\n\t}\n\n\tlet query = NSMetadataQuery()\n\tquery.predicate = NSPredicate(format: metadataQuery)\n\tquery.searchScopes = applicationsFolderURLs\n\n\treturn try await withCheckedThrowingContinuation { continuation in\n\t\tlet alreadyResumed = ManagedAtomic(false)\n\t\tobserver = NotificationCenter.default.addObserver(\n\t\t\tforName: .NSMetadataQueryDidFinishGathering,\n\t\t\tobject: query,\n\t\t\tqueue: nil,\n\t\t) { notification in\n\t\t\tguard !alreadyResumed.exchange(true, ordering: .acquiringAndReleasing) else {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tguard let query = notification.object as? NSMetadataQuery else {\n\t\t\t\tcontinuation.resume(\n\t\t\t\t\tthrowing: MASError.error(\n\t\t\t\t\t\t\"Notification Center returned a \\(type(of: notification.object)) instead of a NSMetadataQuery\",\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tquery.stop()\n\n\t\t\tlet installedApps = query.results\n\t\t\t.compactMap { result in // swiftformat:disable indent\n\t\t\t\t(result as? NSMetadataItem).map { item in\n\t\t\t\t\tInstalledApp(\n\t\t\t\t\t\tadamID: item.value(forAttribute: \"kMDItemAppStoreAdamID\") as? ADAMID ?? 0,\n\t\t\t\t\t\tbundleID: item.value(forAttribute: NSMetadataItemCFBundleIdentifierKey) as? String ?? \"\",\n\t\t\t\t\t\tname: (item.value(forAttribute: \"_kMDItemDisplayNameWithExtensions\") as? String ?? \"\")\n\t\t\t\t\t\t.removingSuffix(\".app\"),\n\t\t\t\t\t\tpath: item.value(forAttribute: NSMetadataItemPathKey) as? String ?? \"\",\n\t\t\t\t\t\tversion: item.value(forAttribute: NSMetadataItemVersionKey) as? String ?? \"\",\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t\t.sorted(using: KeyPathComparator(\\.name, comparator: .localizedStandard)) // swiftformat:enable indent\n\n\t\t\tif ![\"1\", \"true\", \"yes\"].contains(ProcessInfo.processInfo.environment[\"MAS_NO_AUTO_INDEX\"]?.lowercased()) {\n\t\t\t\tlet installedAppPathSet = Set(installedApps.map(\\.path))\n\t\t\t\tfor installedAppURL in applicationsFolderURLs.flatMap(\\.installedAppURLs)\n\t\t\t\twhere !installedAppPathSet.contains(installedAppURL.filePath) { // swiftformat:disable:this indent\n\t\t\t\t\tMAS.printer.warning(\n\t\t\t\t\t\t\"Found a likely App Store app that is not indexed in Spotlight in \",\n\t\t\t\t\t\tinstalledAppURL.filePath,\n\t\t\t\t\t\t\"\"\"\n\n\n\t\t\t\t\t\tIndexing now, which will not complete until sometime after mas exits\n\n\t\t\t\t\t\tDisable auto-indexing via: export MAS_NO_AUTO_INDEX=1\n\t\t\t\t\t\t\"\"\",\n\t\t\t\t\t\tseparator: \"\",\n\t\t\t\t\t)\n\t\t\t\t\tTask {\n\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\t_ = try await run(\n\t\t\t\t\t\t\t\t\"/usr/bin/mdimport\",\n\t\t\t\t\t\t\t\tinstalledAppURL.filePath,\n\t\t\t\t\t\t\t\terrorMessage: \"Failed to index the Spotlight data for \\(installedAppURL.filePath)\",\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tMAS.printer.error(error: error)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcontinuation.resume(returning: installedApps)\n\t\t}\n\n\t\tquery.start()\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Errors/MASError.swift",
    "content": "//\n// MASError.swift\n// mas\n//\n// Copyright © 2015 mas-cli. All rights reserved.\n//\n\nenum MASError: Error {\n\tcase error(String, error: (any Error)? = nil, separator: String = \":\\n\", separatorAndErrorReplacement: String = \"\")\n\tcase noCatalogAppsFound(for: String)\n\tcase unknownAppID(AppID)\n\tcase unparsableURL(String)\n\n\tstatic func error(\n\t\t_ message: String,\n\t\terror: String?,\n\t\tseparator: String = \":\\n\",\n\t\tseparatorAndErrorReplacement: String = \"\",\n\t) -> Self {\n\t\t.error(\n\t\t\tmessage,\n\t\t\terror: error.map { Self.error($0) },\n\t\t\tseparator: separator,\n\t\t\tseparatorAndErrorReplacement: separatorAndErrorReplacement,\n\t\t)\n\t}\n}\n\nextension MASError: CustomStringConvertible {\n\tvar description: String {\n\t\tswitch self {\n\t\tcase let .error(message, error, separator, separatorAndErrorReplacement):\n\t\t\t\"\\(message)\\(error.map { \"\\(separator)\\($0)\" } ?? separatorAndErrorReplacement)\"\n\t\tcase let .noCatalogAppsFound(searchTerm):\n\t\t\t\"No apps found in the App Store for search term: \\(searchTerm)\"\n\t\tcase let .unknownAppID(appID):\n\t\t\t\"No apps found in the App Store for \\(appID)\"\n\t\tcase let .unparsableURL(string):\n\t\t\t\"Failed to parse URL from \\(string)\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Models/AppID.swift",
    "content": "//\n// AppID.swift\n// mas\n//\n// Copyright © 2024 mas-cli. All rights reserved.\n//\n\nenum AppID: CustomStringConvertible {\n\tcase adamID(ADAMID)\n\tcase bundleID(String)\n\n\tvar description: String {\n\t\tswitch self {\n\t\tcase let .adamID(adamID):\n\t\t\t\"ADAM ID \\(adamID)\"\n\t\tcase let .bundleID(bundleID):\n\t\t\t\"bundle ID \\(bundleID)\"\n\t\t}\n\t}\n\n\tvar notInstalledMessage: String {\n\t\t\"No installed apps with \\(self)\"\n\t}\n\n\tinit(from string: String, forceBundleID: Bool = false) {\n\t\tguard !forceBundleID, let adamID = ADAMID(string) else {\n\t\t\tself = .bundleID(string)\n\t\t\treturn\n\t\t}\n\n\t\tself = .adamID(adamID)\n\t}\n}\n\nextension [AppID] { // swiftlint:disable:this file_types_order\n\tfunc lookupCatalogApps(using lookupAppFromAppID: @escaping @Sendable (AppID) async throws -> CatalogApp)\n\tasync -> [CatalogApp] { // swiftformat:disable:this indent\n\t\tawait concurrentCompactMap(attemptingTo: \"lookup app for\", lookupAppFromAppID)\n\t}\n}\n\ntypealias ADAMID = UInt64\n"
  },
  {
    "path": "Sources/mas/Models/CatalogApp.swift",
    "content": "//\n// CatalogApp.swift\n// mas\n//\n// Copyright © 2018 mas-cli. All rights reserved.\n//\n\nstruct CatalogApp {\n\tlet adamID: ADAMID\n\tlet appStorePageURLString: String\n\tlet bundleID: String\n\tlet fileSizeBytes: String\n\tlet formattedPrice: String?\n\tlet minimumOSVersion: String\n\tlet name: String\n\tlet releaseDate: String\n\tlet sellerName: String\n\tlet sellerURLString: String?\n\tlet supportedDevices: [String]? // swiftlint:disable:this discouraged_optional_collection\n\tlet version: String\n\n\tvar displayPrice: String {\n\t\tformattedPrice ?? \"?\"\n\t}\n\n\tinit(\n\t\tadamID: ADAMID = 0,\n\t\tappStorePageURLString: String = \"\",\n\t\tbundleID: String = \"\",\n\t\tfileSizeBytes: String = \"?\",\n\t\tformattedPrice: String? = \"?\",\n\t\tminimumOSVersion: String = \"\",\n\t\tname: String = \"\",\n\t\treleaseDate: String = \"\",\n\t\tsellerName: String = \"\",\n\t\tsellerURLString: String? = nil,\n\t\tsupportedDevices: [String]? = nil, // swiftlint:disable:this discouraged_optional_collection\n\t\tversion: String = \"\",\n\t) {\n\t\tself.adamID = adamID\n\t\tself.appStorePageURLString = appStorePageURLString\n\t\tself.bundleID = bundleID\n\t\tself.fileSizeBytes = fileSizeBytes\n\t\tself.formattedPrice = formattedPrice\n\t\tself.minimumOSVersion = minimumOSVersion\n\t\tself.name = name\n\t\tself.releaseDate = releaseDate\n\t\tself.sellerName = sellerName\n\t\tself.sellerURLString = sellerURLString\n\t\tself.supportedDevices = supportedDevices\n\t\tself.version = version\n\t}\n\n\tfunc with(minimumOSVersion: String) -> Self {\n\t\t.init(\n\t\t\tadamID: adamID,\n\t\t\tappStorePageURLString: appStorePageURLString,\n\t\t\tbundleID: bundleID,\n\t\t\tfileSizeBytes: fileSizeBytes,\n\t\t\tformattedPrice: formattedPrice,\n\t\t\tminimumOSVersion: minimumOSVersion,\n\t\t\tname: name,\n\t\t\treleaseDate: releaseDate,\n\t\t\tsellerName: sellerName,\n\t\t\tsellerURLString: sellerURLString,\n\t\t\tsupportedDevices: supportedDevices,\n\t\t\tversion: version,\n\t\t)\n\t}\n}\n\nextension CatalogApp: Decodable {\n\tenum CodingKeys: String, CodingKey {\n\t\tcase adamID = \"trackId\"\n\t\tcase appStorePageURLString = \"trackViewUrl\"\n\t\tcase bundleID = \"bundleId\"\n\t\tcase fileSizeBytes\n\t\tcase formattedPrice\n\t\tcase minimumOSVersion = \"minimumOsVersion\"\n\t\tcase name = \"trackName\"\n\t\tcase releaseDate = \"currentVersionReleaseDate\"\n\t\tcase sellerName\n\t\tcase sellerURLString = \"sellerUrl\"\n\t\tcase supportedDevices\n\t\tcase version\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Models/CatalogAppResults.swift",
    "content": "//\n// CatalogAppResults.swift\n// mas\n//\n// Copyright © 2018 mas-cli. All rights reserved.\n//\n\nstruct CatalogAppResults: Decodable { // swiftlint:disable:next unused_declaration\n\tlet resultCount: Int // periphery:ignore\n\tlet results: [CatalogApp]\n}\n"
  },
  {
    "path": "Sources/mas/Models/InstalledApp.swift",
    "content": "//\n// InstalledApp.swift\n// mas\n//\n// Copyright © 2018 mas-cli. All rights reserved.\n//\n\nstruct InstalledApp {\n\tlet adamID: ADAMID\n\tlet bundleID: String\n\tlet name: String\n\tlet path: String\n\tlet version: String\n\n\tvar isTestFlight: Bool {\n\t\tadamID == 0\n\t}\n\n\tfunc matches(_ appID: AppID) -> Bool {\n\t\tswitch appID {\n\t\tcase let .adamID(adamID):\n\t\t\tself.adamID == adamID\n\t\tcase let .bundleID(bundleID):\n\t\t\tself.bundleID == bundleID\n\t\t}\n\t}\n}\n\nextension [InstalledApp] {\n\tfunc filter(for appIDs: [AppID]) -> [Element] {\n\t\tappIDs.isEmpty\n\t\t? self // swiftformat:disable:this indent\n\t\t: appIDs.flatMap { appID in\n\t\t\tlet installedApps = filter { $0.matches(appID) }\n\t\t\tif installedApps.isEmpty {\n\t\t\t\tMAS.printer.error(appID.notInstalledMessage)\n\t\t\t}\n\t\t\treturn installedApps\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Models/OutdatedApp.swift",
    "content": "//\n// OutdatedApp.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\ninternal import ArgumentParser\nprivate import Atomics\nprivate import Foundation\nprivate import StoreFoundation\n\ntypealias OutdatedApp = (\n\tinstalledApp: InstalledApp,\n\tnewVersion: String,\n)\n\nextension [InstalledApp] {\n\tfunc outdatedApps(\n\t\tfilterFor appIDs: [AppID], // swiftlint:disable:next unneeded_escaping\n\t\tlookupAppFromAppID: @escaping @Sendable (AppID) async throws -> CatalogApp,\n\t\taccuracy: OutdatedAccuracy,\n\t\tshouldCheckMinimumOSVersion: Bool,\n\t\tshouldWarnIfUnknownApp: Bool,\n\t) async -> [OutdatedApp] {\n\t\t@Sendable\n\t\tfunc installableCatalogApp(from installedApp: InstalledApp) async -> CatalogApp? {\n\t\t\tdo {\n\t\t\t\tlet catalogApp = try await lookupAppFromAppID(.bundleID(installedApp.bundleID))\n\t\t\t\treturn shouldCheckMinimumOSVersion // swiftformat:disable indent\n\t\t\t\t&& UniversalSemVerInt(from: catalogApp.minimumOSVersion).flatMap { minimumOSVersion in\n\t\t\t\t\tProcessInfo.processInfo.isOperatingSystemAtLeast(\n\t\t\t\t\t\tOperatingSystemVersion(\n\t\t\t\t\t\t\tmajorVersion: minimumOSVersion.majorInteger,\n\t\t\t\t\t\t\tminorVersion: minimumOSVersion.minorInteger,\n\t\t\t\t\t\t\tpatchVersion: minimumOSVersion.patchInteger,\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\t== false ? nil : catalogApp\n\t\t\t} catch { // swiftformat:enable indent\n\t\t\t\tif let error = error as? MASError, case MASError.unknownAppID = error {\n\t\t\t\t\tif shouldWarnIfUnknownApp {\n\t\t\t\t\t\tMAS.printer.warning(error, \"; was expected to identify: \", installedApp.name, separator: \"\")\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tMAS.printer.error(error: error)\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\t\treturn await filter(for: appIDs).concurrentCompactMap(\n\t\t\taccuracy == .accurate\n\t\t\t? { @Sendable installedApp in // swiftformat:disable indent\n\t\t\t\tif shouldCheckMinimumOSVersion, await installableCatalogApp(from: installedApp) == nil {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\treturn await withCheckedContinuation { continuation in\n\t\t\t\t\tTask {\n\t\t\t\t\t\tlet alreadyResumed = ManagedAtomic(false)\n\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\ttry await AppStore.install.app(withADAMID: installedApp.adamID) { appStoreVersion, shouldOutput in\n\t\t\t\t\t\t\t\tif\n\t\t\t\t\t\t\t\t\tshouldOutput,\n\t\t\t\t\t\t\t\t\tlet appStoreVersion,\n\t\t\t\t\t\t\t\t\tinstalledApp.version != appStoreVersion,\n\t\t\t\t\t\t\t\t\t!alreadyResumed.exchange(true, ordering: .acquiringAndReleasing)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tcontinuation.resume(returning: OutdatedApp(installedApp, appStoreVersion))\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn true\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tMAS.printer.error(error: error)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif !alreadyResumed.load(ordering: .acquiring) {\n\t\t\t\t\t\t\tcontinuation.resume(returning: nil)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t: { @Sendable installedApp in\n\t\t\t\tawait installableCatalogApp(from: installedApp).flatMap { catalogApp in\n\t\t\t\t\tUniversalSemVer(from: installedApp.version).compareSemVerAndBuild(to: .init(from: catalogApp.version))\n\t\t\t\t\t== .orderedAscending ? OutdatedApp(installedApp, catalogApp.version) : nil\n\t\t\t\t}\n\t\t\t},\n\t\t) // swiftformat:enable indent\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Network/URL.swift",
    "content": "//\n// URL.swift\n// mas\n//\n// Copyright © 2024 mas-cli. All rights reserved.\n//\n\ninternal import AppKit\nprivate import Foundation\nprivate import ObjectiveC\n\nextension URL {\n\tvar filePath: String {\n\t\t.init(path(percentEncoded: false).dropLast { $0 == \"/\" })\n\t}\n\n\tfunc open(configuration: NSWorkspace.OpenConfiguration = NSWorkspace.OpenConfiguration()) async throws {\n\t\ttry await NSWorkspace.shared.open(self, configuration: configuration)\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Utilities/Collection.swift",
    "content": "//\n// Collection.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\nextension Collection {\n\tfunc dropLast(while predicate: (Element) throws -> Bool) rethrows -> SubSequence {\n\t\ttry indices.reversed().first { try !predicate(self[$0]) }.map { self[...$0] } ?? self[endIndex...]\n\t}\n}\n\nextension Collection where Element: Sendable {\n\tfunc concurrentMap<T: Sendable>(\n\t\tmaxConcurrentTaskCount: Int = defaultMaxConcurrentTaskCount,\n\t\t_ transform: @escaping @Sendable (Element) async -> T,\n\t) async -> [T] { // swiftlint:disable:next force_unwrapping\n\t\tawait concurrentTransform(maxConcurrentTaskCount: maxConcurrentTaskCount, transform).map { $0! }\n\t}\n\n\tfunc concurrentMap<T: Sendable>(\n\t\tmaxConcurrentTaskCount: Int = defaultMaxConcurrentTaskCount,\n\t\t_ transform: @escaping @Sendable (Element) async throws -> T,\n\t) async rethrows -> [T] { // periphery:ignore\n\t\ttry await concurrentTransform(maxConcurrentTaskCount: maxConcurrentTaskCount, transform).map { $0! }\n\t} // swiftlint:disable:previous force_unwrapping\n\n\tfunc concurrentCompactMap<T: Sendable>(\n\t\tmaxConcurrentTaskCount: Int = defaultMaxConcurrentTaskCount,\n\t\t_ transform: @escaping @Sendable (Element) async -> T?,\n\t) async -> [T] {\n\t\tawait concurrentTransform(maxConcurrentTaskCount: maxConcurrentTaskCount, transform).compactMap(\\.self)\n\t}\n\n\tfunc concurrentCompactMap<T: Sendable>(\n\t\tmaxConcurrentTaskCount: Int = defaultMaxConcurrentTaskCount,\n\t\t_ transform: @escaping @Sendable (Element) async throws -> T?,\n\t) async rethrows -> [T] { // periphery:ignore\n\t\ttry await concurrentTransform(maxConcurrentTaskCount: maxConcurrentTaskCount, transform).compactMap(\\.self)\n\t}\n\n\tfunc concurrentCompactMap<T: Sendable, E: Error>(\n\t\tattemptingTo perform: String,\n\t\tmaxConcurrentTaskCount: Int = defaultMaxConcurrentTaskCount,\n\t\t_ transform: @escaping @Sendable (Element) async throws(E) -> T?,\n\t) async -> [T] {\n\t\tawait concurrentCompactMap(maxConcurrentTaskCount: maxConcurrentTaskCount) { element in\n\t\t\tdo {\n\t\t\t\treturn try await transform(element)\n\t\t\t} catch {\n\t\t\t\tMAS.printer.error(error is MASError ? [] : [\"Failed to\", perform, element], error: error)\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate func concurrentTransform<T: Sendable>(\n\t\tmaxConcurrentTaskCount: Int,\n\t\t_ transform: @escaping @Sendable (Element) async throws -> T?,\n\t) async rethrows -> [T?] {\n\t\ttry await withThrowingTaskGroup(of: (index: Int, result: T?).self) { group in\n\t\t\tvar iterator = enumerated().makeIterator()\n\t\t\tfunc addNextTask() {\n\t\t\t\tif let next = iterator.next() {\n\t\t\t\t\tgroup.addTask {\n\t\t\t\t\t\t(next.offset, try await transform(next.element))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor _ in 0..<Swift.min(count, maxConcurrentTaskCount) {\n\t\t\t\taddNextTask()\n\t\t\t}\n\n\t\t\treturn try await group.reduce(into: [T?](repeating: nil, count: count)) { results, indexedResult in\n\t\t\t\tresults[indexedResult.index] = indexedResult.result\n\t\t\t\taddNextTask()\n\t\t\t}\n\t\t}\n\t}\n}\n\nprivate let defaultMaxConcurrentTaskCount = 16\n"
  },
  {
    "path": "Sources/mas/Utilities/FileHandle.swift",
    "content": "//\n// FileHandle.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\nprivate import Darwin\ninternal import Foundation\n\nextension FileHandle {\n\tvar isTerminal: Bool {\n\t\tisatty(fileDescriptor) != 0\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Utilities/Group.swift",
    "content": "//\n// Group.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\ninternal import Darwin\n\nprivate extension gid_t {\n\tvar nameAndID: String {\n\t\t\"\\(unsafe String(cString: unsafe getgrgid(self).pointee.gr_name).quoted) (\\(self))\"\n\t}\n}\n\nfunc set(effectiveGID gid: gid_t) throws {\n\tguard setegid(gid) == 0 else {\n\t\tthrow MASError.error(\"Failed to switch effective group from \\(getegid().nameAndID) to \\(gid.nameAndID)\")\n\t}\n}\n\nfunc reset(effectiveGID gid: gid_t) {\n\tdo {\n\t\ttry set(effectiveGID: gid)\n\t} catch {\n\t\tMAS.printer.warning(error: error)\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Utilities/KeyPath.swift",
    "content": "//\n// KeyPath.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\nprefix func ! <Root>(keyPath: KeyPath<Root, Bool>) -> (Root) -> Bool { // swiftlint:disable:this static_operator\n\t{ !$0[keyPath: keyPath] }\n}\n"
  },
  {
    "path": "Sources/mas/Utilities/Optional.swift",
    "content": "//\n// Optional.swift\n// mas\n//\n// Copyright © 2026 mas-cli. All rights reserved.\n//\n\nextension Optional {\n\t// periphery:ignore\n\tfunc map<E: Error, U: ~Copyable>(_ transform: (Wrapped) async throws(E) -> U) async throws(E) -> U? {\n\t\tguard let self else { // swiftlint:disable:previous unused_declaration\n\t\t\treturn nil\n\t\t}\n\n\t\treturn try await transform(self)\n\t}\n\n\tfunc flatMap<E: Error, U: ~Copyable>(_ transform: (Wrapped) async throws(E) -> U?) async throws(E) -> U? {\n\t\tguard let self else {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn try await transform(self)\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Utilities/Pipe.swift",
    "content": "//\n// Pipe.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\ninternal import Foundation\n\nextension Pipe {\n\tfunc readToEnd(encoding: String.Encoding = .utf8) throws -> String? {\n\t\ttry fileHandleForReading.readToEnd().flatMap { .init(data: $0, encoding: encoding) }\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Utilities/Printer.swift",
    "content": "//\n// Printer.swift\n// mas\n//\n// Copyright © 2016 mas-cli. All rights reserved.\n//\n\nprivate import ArgumentParser\nprivate import Atomics\ninternal import Foundation\n\n/// Prints to `stdout` and `stderr` with ANSI color codes when connected to a\n/// terminal.\nstruct Printer {\n\tprivate let errorCounter = ManagedAtomic<UInt64>(0)\n\n\tvar errorCount: UInt64 {\n\t\terrorCounter.load(ordering: .acquiring)\n\t}\n\n\tfunc resetErrorCount() { // periphery:ignore\n\t\terrorCounter.store(0, ordering: .releasing) // swiftlint:disable:previous unused_declaration\n\t}\n\n\t/// Prints to `stdout`.\n\t@_disfavoredOverload\n\tfunc info(_ items: Any..., separator: String = \" \", terminator: String = \"\\n\") {\n\t\tinfo(items, separator: separator, terminator: terminator)\n\t}\n\n\t/// Prints to `stdout`.\n\tfunc info(_ items: [Any], separator: String = \" \", terminator: String = \"\\n\") {\n\t\tprint(items.map(String.init(describing:)), separator: separator, terminator: terminator, to: .standardOutput)\n\t}\n\n\t/// Prints to `stdout`, prefixed with \"==> \"; if connected to a terminal, the\n\t/// prefix is blue.\n\t@_disfavoredOverload\n\tfunc notice(_ items: Any..., separator: String = \" \", terminator: String = \"\\n\") {\n\t\tnotice(items, separator: separator, terminator: terminator)\n\t}\n\n\t/// Prints to `stdout`, prefixed with \"==> \"; if connected to a terminal, the\n\t/// prefix is blue.\n\tfunc notice(_ items: [Any], separator: String = \" \", terminator: String = \"\\n\") {\n\t\tprint(items, prefix: \"==>\", format: \"1;34\", separator: separator, terminator: terminator, to: .standardOutput)\n\t}\n\n\t/// Prints to `stderr`, prefixed with \"Warning: \"; if connected to a terminal,\n\t/// the prefix is yellow & underlined.\n\t@_disfavoredOverload\n\tfunc warning(_ items: Any..., error: (any Error)? = nil, separator: String = \" \", terminator: String = \"\\n\") {\n\t\twarning(items, error: error, separator: separator, terminator: terminator)\n\t}\n\n\t/// Prints to `stderr`, prefixed with \"Warning: \"; if connected to a terminal,\n\t/// the prefix is yellow & underlined.\n\tfunc warning(_ items: [Any], error: (any Error)? = nil, separator: String = \" \", terminator: String = \"\\n\") {\n\t\tproblem(items, prefix: \"Warning:\", format: \"4;33\", error: error, separator: separator, terminator: terminator)\n\t}\n\n\t/// Prints to `stderr`, prefixed with \"Error: \"; if connected to a terminal,\n\t/// the prefix is red & underlined.\n\t@_disfavoredOverload\n\tfunc error(_ items: Any..., error: (any Error)? = nil, separator: String = \" \", terminator: String = \"\\n\") {\n\t\tself.error(items, error: error, separator: separator, terminator: terminator)\n\t}\n\n\t/// Prints to `stderr`, prefixed with \"Error: \"; if connected to a terminal,\n\t/// the prefix is red & underlined.\n\tfunc error(_ items: [Any], error: (any Error)? = nil, separator: String = \" \", terminator: String = \"\\n\") {\n\t\terrorCounter.wrappingIncrement(ordering: .relaxed)\n\t\tproblem(items, prefix: errorPrefix, format: errorFormat, error: error, separator: separator, terminator: terminator)\n\t}\n\n\tfunc clearCurrentLine(of fileHandle: FileHandle) {\n\t\tif fileHandle.isTerminal {\n\t\t\tdo {\n\t\t\t\ttry fileHandle.write(contentsOf: Data(\"\\(csi)2K\\(csi)0G\".utf8))\n\t\t\t} catch {\n\t\t\t\t// Do nothing\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate func problem(\n\t\t_ items: [Any],\n\t\tprefix: String,\n\t\tformat: String,\n\t\terror: (any Error)?,\n\t\tseparator: String,\n\t\tterminator: String,\n\t) {\n\t\tguard !items.isEmpty || (error != nil && !(error is ExitCode)) else {\n\t\t\treturn\n\t\t}\n\n\t\tprint(\n\t\t\titems,\n\t\t\tprefix: prefix,\n\t\t\tformat: format,\n\t\t\tseparator: separator,\n\t\t\tterminator: error.map { error in\n\t\t\t\tlet errorDescription = String(describing: error)\n\t\t\t\treturn \"\\(errorDescription.isEmpty ? \"\" : items.isEmpty ? \" \" : \"\\n\")\\(errorDescription)\\(terminator)\"\n\t\t\t}\n\t\t\t?? terminator, // swiftformat:disable:this indent\n\t\t\tto: .standardError,\n\t\t)\n\t}\n\n\tprivate func print(_ items: [String], separator: String, terminator: String, to fileHandle: FileHandle) {\n\t\tdo {\n\t\t\ttry fileHandle.write(contentsOf: Data(items.joined(separator: separator).appending(terminator).utf8))\n\t\t} catch {\n\t\t\t// Do nothing\n\t\t}\n\t}\n\n\tprivate func print(\n\t\t_ items: [Any],\n\t\tprefix: String,\n\t\tformat: String,\n\t\tseparator: String,\n\t\tterminator: String,\n\t\tto fileHandle: FileHandle,\n\t) { // swiftformat:disable indent\n\t\tlet indent = \"\"\"\n\n\t\t\t\\(\n\t\t\t\tString( // swiftlint:disable:this indentation_width\n\t\t\t\t\trepeating: \" \",\n\t\t\t\t\tcount:\n\t\t\t\t\t\t(prefix.range(of: \"\\n\", options: .backwards).map { .init(prefix[$0.upperBound...]) } ?? prefix).count + 1,\n\t\t\t\t)\n\t\t\t)\n\t\t\t\"\"\"\n\n\t\tlet formattedPrefix = prefix.formatted(with: format, for: fileHandle) // swiftformat:enable indent\n\t\tprint(\n\t\t\titems.first.map { item in\n\t\t\t\t[\"\\(formattedPrefix) \\(mas.indent(item, with: indent))\"]\n\t\t\t\t+ items.dropFirst().map { mas.indent($0, with: indent) } // swiftformat:disable:this indent\n\t\t\t}\n\t\t\t?? [formattedPrefix], // swiftformat:disable:this indent\n\t\t\tseparator: mas.indent(separator, with: indent),\n\t\t\tterminator: terminator,\n\t\t\tto: fileHandle,\n\t\t)\n\t}\n}\n\nextension String {\n\tfunc formatted(with format: Self, for fileHandle: FileHandle) -> Self {\n\t\tfileHandle.isTerminal ? \"\\(csi)\\(format)m\\(self)\\(csi)0m\" : self\n\t}\n}\n\nprivate func indent(_ item: Any, with indent: String) -> String {\n\t.init(describing: item).replacing(unsafe nonEmptyLineStartRegex, with: indent)\n}\n\nlet errorPrefix = \"Error:\"\nlet errorFormat = \"4;31\"\n\n/// Terminal Control Sequence Indicator.\nprivate let csi = \"\\u{001B}[\"\n\nprivate nonisolated(unsafe) let nonEmptyLineStartRegex = /\\n(?!\\n)/\n"
  },
  {
    "path": "Sources/mas/Utilities/Process.swift",
    "content": "//\n// Process.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\ninternal import Foundation\nprivate import ObjectiveC\n\nfunc run(\n\t_ executablePath: String,\n\t_ args: String...,\n\terrorMessage: @autoclosure () -> String,\n\trunProcess run: (Process) throws -> Void = { try $0.run() },\n) async throws -> (standardOutputString: String, standardErrorString: String) {\n\tlet process = Process()\n\tprocess.executableURL = URL(filePath: executablePath, directoryHint: .notDirectory)\n\tprocess.arguments = args\n\n\tlet standardOutputPipe = Pipe()\n\tlet standardErrorPipe = Pipe()\n\n\tprocess.standardOutput = standardOutputPipe\n\tprocess.standardError = standardErrorPipe\n\n\tlet standardOutputTask = Task(priority: .background) {\n\t\ttry standardOutputPipe.readToEnd()?.trimmingCharacters(in: .whitespacesAndNewlines) ?? \"\"\n\t}\n\tlet standardErrorTask = Task(priority: .background) {\n\t\ttry standardErrorPipe.readToEnd()?.trimmingCharacters(in: .whitespacesAndNewlines) ?? \"\"\n\t}\n\n\tdo {\n\t\ttry run(process)\n\t} catch {\n\t\tthrow MASError.error(errorMessage(), error: error)\n\t}\n\tprocess.waitUntilExit()\n\n\tlet standardOutputString = try await standardOutputTask.value\n\tlet standardErrorString = try await standardErrorTask.value\n\n\tguard process.terminationStatus == 0 else {\n\t\tthrow MASError.error(\n\t\t\t\"\"\"\n\t\t\t\\(errorMessage())\n\t\t\tExit status: \\(process.terminationStatus)\\\n\t\t\t\\(standardOutputString.ifNotEmptyPrepend(\"\\n\\nStandard output:\\n\"))\\\n\t\t\t\\(standardErrorString.ifNotEmptyPrepend(\"\\n\\nStandard error:\\n\"))\n\t\t\t\"\"\",\n\t\t)\n\t}\n\n\treturn (standardOutputString, standardErrorString)\n}\n\nprivate extension String {\n\tfunc ifNotEmptyPrepend(_ prefix: String) -> Self {\n\t\tisEmpty ? self : prefix + self\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Utilities/ProcessInfo.swift",
    "content": "//\n// ProcessInfo.swift\n// mas\n//\n// Copyright © 2024 mas-cli. All rights reserved.\n//\n\ninternal import Darwin\nprivate import Foundation\n\nextension ProcessInfo {\n\tvar sudoUID: uid_t {\n\t\tget throws {\n\t\t\ttry environment[\"SUDO_UID\"].flatMap(uid_t.init) ?? { throw MASError.error(\"Failed to get sudo uid\") }()\n\t\t}\n\t}\n\n\tvar sudoGID: gid_t {\n\t\tget throws {\n\t\t\ttry environment[\"SUDO_GID\"].flatMap(gid_t.init) ?? { throw MASError.error(\"Failed to get sudo gid\") }()\n\t\t}\n\t}\n\n\tfunc runAsSudoEffectiveUserAndSudoEffectiveGroup<T>(_ body: () throws -> T) throws -> T {\n\t\ttry run(asEffectiveUID: sudoUID, andEffectiveGID: sudoGID, body)\n\t}\n\n\tfunc runAsSudoEffectiveUserAndSudoEffectiveGroup<T>(_ body: () async throws -> T) async throws -> T {\n\t\ttry await run(asEffectiveUID: sudoUID, andEffectiveGID: sudoGID, body)\n\t}\n\n\tfunc runAsSudoEffectiveUserAndSudoEffectiveGroupIfRootEffectiveUser<T>(_ body: () throws -> T) throws -> T {\n\t\tgeteuid() == 0 ? try runAsSudoEffectiveUserAndSudoEffectiveGroup(body) : try body()\n\t}\n\n\tfunc runAsSudoEffectiveUserAndSudoEffectiveGroupIfRootEffectiveUser<T>(_ body: () async throws -> T)\n\tasync throws -> T { // swiftformat:disable:this indent\n\t\tgeteuid() == 0 ? try await runAsSudoEffectiveUserAndSudoEffectiveGroup(body) : try await body()\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Utilities/RangeReplaceableCollection.swift",
    "content": "//\n// RangeReplaceableCollection.swift\n// mas\n//\n// Copyright © 2026 mas-cli. All rights reserved.\n//\n\nextension RangeReplaceableCollection {\n\tfunc padding(toCount minimumCount: Int, with padValue: Element) -> Self {\n\t\tlet appendCount = minimumCount - count\n\t\treturn appendCount > 0 ? self + repeatElement(padValue, count: appendCount) : self\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Utilities/Sequence.swift",
    "content": "//\n// Sequence.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\nextension Sequence {\n\tfunc forEach<E: Error>(attemptTo perform: String, _ body: (Element) async throws(E) -> Void) async {\n\t\tawait forEach(body) { MAS.printer.error($1 is MASError ? [] : [\"Failed to\", perform, $0], error: $1) }\n\t}\n\n\tprivate func forEach<E: Error>(\n\t\t_ body: (Element) async throws(E) -> Void,\n\t\thandlingErrors errorHandler: (Element, E) async -> Void,\n\t) async {\n\t\tfor element in self {\n\t\t\tdo {\n\t\t\t\ttry await body(element)\n\t\t\t} catch {\n\t\t\t\tawait errorHandler(element, error)\n\t\t\t}\n\t\t}\n\t}\n}\n\nextension Sequence {\n\t/// Merge two sequences by greedily selecting the element with the higher score.\n\t/// Preserves the relative order of elements within their original sequences.\n\tfunc priorityMerge(_ secondary: some Sequence<Element>, score: (Element) -> Double) -> [Element] {\n\t\tvar merged = [Element]()\n\n\t\tif let primary = self as? any Collection, let secondary = secondary as? any Collection {\n\t\t\tmerged.reserveCapacity(primary.count + secondary.count)\n\t\t}\n\n\t\tvar primaryIterator = makeIterator()\n\t\tvar secondaryIterator = secondary.makeIterator()\n\n\t\tvar primaryItemAndScore: (item: Element, score: Double)? = primaryIterator.next().map { ($0, score($0)) }\n\t\tvar secondaryItemAndScore: (item: Element, score: Double)? = secondaryIterator.next().map { ($0, score($0)) }\n\n\t\twhile let primaryInfo = primaryItemAndScore, let secondaryInfo = secondaryItemAndScore {\n\t\t\tif primaryInfo.score >= secondaryInfo.score {\n\t\t\t\tmerged.append(primaryInfo.item)\n\t\t\t\tprimaryItemAndScore = primaryIterator.next().map { ($0, score($0)) }\n\t\t\t} else {\n\t\t\t\tmerged.append(secondaryInfo.item)\n\t\t\t\tsecondaryItemAndScore = secondaryIterator.next().map { ($0, score($0)) }\n\t\t\t}\n\t\t}\n\n\t\tif let primaryItemAndScore {\n\t\t\tmerged.append(primaryItemAndScore.item)\n\t\t\twhile let item = primaryIterator.next() {\n\t\t\t\tmerged.append(item)\n\t\t\t}\n\t\t} else if let secondaryItemAndScore {\n\t\t\tmerged.append(secondaryItemAndScore.item)\n\t\t\twhile let item = secondaryIterator.next() {\n\t\t\t\tmerged.append(item)\n\t\t\t}\n\t\t}\n\n\t\treturn merged\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Utilities/String.swift",
    "content": "//\n// String.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\nprivate import Foundation\n\nextension String {\n\tvar quoted: Self {\n\t\t\"'\\(replacing(\"'\", with: \"\\\\'\"))'\"\n\t}\n\n\tfunc removingSuffix(_ suffix: Self) -> Self {\n\t\thasSuffix(suffix) ? Self(dropLast(suffix.count)) : self\n\t}\n\n\tfunc similarity(to other: Self) -> Double {\n\t\tlet this = Array(precomposedStringWithCanonicalMapping)\n\t\tlet that = Array(other.precomposedStringWithCanonicalMapping)\n\t\tlet thisLength = this.count\n\t\tlet thatLength = that.count\n\t\tguard thisLength > 0 || thatLength > 0 else {\n\t\t\treturn 1.0\n\t\t}\n\t\tguard thisLength != 0, thatLength != 0 else {\n\t\t\treturn 0.0\n\t\t}\n\n\t\t// 2D matrix for Damerau-Levenshtein to track transpositions\n\t\tvar matrix = Array(repeating: Array(repeating: 0.0, count: thatLength + 1), count: thisLength + 1)\n\n\t\t// Initialize base costs (deletions/insertions)\n\t\tfor index in 0...thisLength {\n\t\t\tmatrix[index][0] = Double(index)\n\t\t}\n\t\tfor index in 0...thatLength {\n\t\t\tmatrix[0][index] = Double(index)\n\t\t}\n\n\t\tfor i in 1...thisLength { // swiftlint:disable:this identifier_name\n\t\t\tfor j in 1...thatLength { // swiftlint:disable:this identifier_name\n\t\t\t\tlet thisChar = this[i - 1]\n\t\t\t\tlet thatChar = that[j - 1]\n\t\t\t\tif thisChar == thatChar {\n\t\t\t\t\tmatrix[i][j] = matrix[i - 1][j - 1]\n\t\t\t\t} else {\n\t\t\t\t\t// Standard edit costs\n\t\t\t\t\tlet cost = Swift.min(\n\t\t\t\t\t\tmatrix[i - 1][j] + thisChar.structuralCost, // Deletion\n\t\t\t\t\t\tmatrix[i][j - 1] + thatChar.structuralCost, // Insertion\n\t\t\t\t\t\tmatrix[i - 1][j - 1] + thisChar.substitutionCost(for: thatChar),\n\t\t\t\t\t)\n\n\t\t\t\t\tmatrix[i][j] = i > 1 && j > 1 && this[i - 1] == that[j - 2] && this[i - 2] == that[j - 1] // Transposition\n\t\t\t\t\t? Swift.min(cost, matrix[i - 2][j - 2] + 0.4) // swiftformat:disable:this indent\n\t\t\t\t\t: cost\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn max(0, 1.0 - (matrix[thisLength][thatLength] / Double(max(thisLength, thatLength))))\n\t}\n}\n\nprivate extension Character {\n\tvar structuralCost: Double {\n\t\tisWhitespace || isPunctuation || isSymbol ? 0.25 : 1.0\n\t}\n\n\tfunc substitutionCost(for char: Character) -> Double {\n\t\tString(self).folding(options: .diacriticInsensitive, locale: .current)\n\t\t== String(char).folding(options: .diacriticInsensitive, locale: .current) // swiftformat:disable:this indent\n\t\t? 0.1 // swiftformat:disable:this indent\n\t\t: lowercased() == char.lowercased() ? 0.2 : 1.0\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Utilities/Sudo.swift",
    "content": "//\n// Sudo.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\nprivate import ArgumentParser\nprivate import Darwin\nprivate import Foundation\n\nfunc sudo(_ executableName: String, args: some Sequence<String>) throws {\n\tguard let executablePath = Bundle.main.executableURL?.filePath else {\n\t\tthrow MASError.error(\"Failed to get the executable path for sudo \\(executableName) \\(args.joined(separator: \" \"))\")\n\t}\n\n\ttry sudo([executablePath] + args)\n}\n\nprivate func sudo(_ args: some Sequence<String>) throws {\n\tlet cArgs = unsafe ([\"sudo\", \"MAS_NO_AUTO_INDEX=1\"] + args).map { unsafe strdup($0) }\n\tdefer {\n\t\tfor unsafe cArg in unsafe cArgs {\n\t\t\tunsafe free(cArg)\n\t\t}\n\t}\n\n\tvar pid = 0 as pid_t\n\tlet spawnStatus = unsafe posix_spawn(&pid, \"/usr/bin/sudo\", nil, nil, cArgs + [nil], environ)\n\tguard spawnStatus == 0 else {\n\t\tthrow MASError.error(\n\t\t\t\"Failed to spawn installer process\",\n\t\t\terror: unsafe String(cString: strerror(spawnStatus)),\n\t\t\tseparator: \": \",\n\t\t)\n\t}\n\n\tvar sudoStatus = 0 as Int32\n\tunsafe waitpid(pid, &sudoStatus, 0)\n\tguard sudoStatus == 0 else {\n\t\tthrow ExitCode(max((sudoStatus >> 8) & 0xff, 1))\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Utilities/User.swift",
    "content": "//\n// User.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\ninternal import Darwin\n\nprivate extension uid_t {\n\tvar nameAndID: String {\n\t\t\"\\(unsafe String(cString: unsafe getpwuid(self).pointee.pw_name).quoted) (\\(self))\"\n\t}\n}\n\nfunc set(effectiveUID uid: uid_t) throws {\n\tguard seteuid(uid) == 0 else {\n\t\tthrow MASError.error(\"Failed to switch effective user from \\(geteuid().nameAndID) to \\(uid.nameAndID)\")\n\t}\n}\n\nfunc reset(effectiveUID uid: uid_t) {\n\tdo {\n\t\ttry set(effectiveUID: uid)\n\t} catch {\n\t\tMAS.printer.warning(error: error)\n\t}\n}\n"
  },
  {
    "path": "Sources/mas/Utilities/UserAndGroup.swift",
    "content": "//\n// UserAndGroup.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\ninternal import Darwin\n\nfunc run<T>(asEffectiveUID uid: uid_t, andEffectiveGID gid: gid_t, _ body: () throws -> T) throws -> T {\n\tlet originalEffectiveUID = geteuid()\n\tlet originalEffectiveGID = getegid()\n\tguard originalEffectiveUID == 0 else {\n\t\ttry set(effectiveUID: uid)\n\t\tdefer {\n\t\t\treset(effectiveUID: originalEffectiveUID)\n\t\t}\n\t\ttry set(effectiveGID: gid)\n\t\tdefer {\n\t\t\treset(effectiveGID: originalEffectiveGID)\n\t\t}\n\t\treturn try body()\n\t}\n\n\ttry set(effectiveGID: gid)\n\tdefer {\n\t\treset(effectiveGID: originalEffectiveGID)\n\t}\n\ttry set(effectiveUID: uid)\n\tdefer {\n\t\treset(effectiveUID: originalEffectiveUID)\n\t}\n\treturn try body()\n}\n\nfunc run<T>(asEffectiveUID uid: uid_t, andEffectiveGID gid: gid_t, _ body: () async throws -> T) async throws -> T {\n\tlet originalEffectiveUID = geteuid()\n\tlet originalEffectiveGID = getegid()\n\tguard originalEffectiveUID == 0 else {\n\t\ttry set(effectiveUID: uid)\n\t\tdefer {\n\t\t\treset(effectiveUID: originalEffectiveUID)\n\t\t}\n\t\ttry set(effectiveGID: gid)\n\t\tdefer {\n\t\t\treset(effectiveGID: originalEffectiveGID)\n\t\t}\n\t\treturn try await body()\n\t}\n\n\ttry set(effectiveGID: gid)\n\tdefer {\n\t\treset(effectiveGID: originalEffectiveGID)\n\t}\n\ttry set(effectiveUID: uid)\n\tdefer {\n\t\treset(effectiveUID: originalEffectiveUID)\n\t}\n\treturn try await body()\n}\n"
  },
  {
    "path": "Sources/mas/Utilities/Version+SemVer.swift",
    "content": "//\n// Version+SemVer.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\nprivate import BigInt\ninternal import Foundation\n\n// swiftlint:disable:next blanket_disable_command\n// swiftlint:disable file_types_order one_declaration_per_file\n\nprotocol Version: CustomStringConvertible {\n\tvar coreElements: [String] { get }\n\tvar prereleaseElements: [String] { get }\n\tvar buildElements: [String] { get }\n\n\tvar core: String { get }\n\tvar prerelease: String? { get }\n\tvar build: String? { get }\n\n\tinit?(from versionString: String) // periphery:ignore\n}\n\nprotocol CoreIntegerVersion: Version {\n\tassociatedtype Integer: BinaryInteger\n\n\tvar coreIntegers: [Integer] { get }\n}\n\nextension CoreIntegerVersion where Integer: FixedWidthInteger {\n\tvar coreElements: [String] {\n\t\tcoreIntegers.map { .init($0) }\n\t}\n}\n\nprotocol MajorMinorPatch { // swiftlint:disable unused_declaration\n\tvar major: String { get } // periphery:ignore\n\tvar minor: String { get } // periphery:ignore\n\tvar patch: String { get } // periphery:ignore\n} // swiftlint:enable unused_declaration\n\nprotocol MajorMinorPatchInteger: MajorMinorPatch {\n\tassociatedtype Integer: BinaryInteger\n\n\tvar majorInteger: Integer { get }\n\tvar minorInteger: Integer { get }\n\tvar patchInteger: Integer { get }\n}\n\nextension MajorMinorPatchInteger {\n\tvar major: String {\n\t\t.init(majorInteger)\n\t}\n\n\tvar minor: String {\n\t\t.init(minorInteger)\n\t}\n\n\tvar patch: String {\n\t\t.init(patchInteger)\n\t}\n}\n\nprotocol SemVerSyntax: Version {}\n\nextension SemVerSyntax {\n\tvar core: String {\n\t\tcoreElements.joined(separator: \".\")\n\t}\n\n\tvar prerelease: String? {\n\t\tprereleaseElements.isEmpty ? nil : prereleaseElements.joined(separator: \".\")\n\t}\n\n\tvar build: String? {\n\t\tbuildElements.isEmpty ? nil : buildElements.joined(separator: \".\")\n\t}\n\n\tvar description: String {\n\t\t\"\\(core)\\(prerelease.map { \"-\\($0)\" } ?? \"\")\\(build.map { \"+\\($0)\" } ?? \"\")\"\n\t}\n}\n\nprotocol SemVerSyntaxInteger: CoreIntegerVersion, SemVerSyntax, MajorMinorPatchInteger {}\n\nstruct UniversalSemVerInt: SemVerSyntaxInteger {\n\ttypealias Integer = Int\n\n\tlet coreIntegers: [Integer]\n\tlet prereleaseElements: [String]\n\tlet buildElements: [String]\n\n\tvar majorInteger: Integer {\n\t\tcoreIntegers[0]\n\t}\n\n\tvar minorInteger: Integer {\n\t\tcoreIntegers[1]\n\t}\n\n\tvar patchInteger: Integer {\n\t\tcoreIntegers[2]\n\t}\n\n\tinit(\n\t\tcoreIntegers: [Integer],\n\t\tprereleaseElements: [String] = [],\n\t\tbuildElements: [String] = [],\n\t) {\n\t\tself.coreIntegers = coreIntegers.padding(toCount: 3, with: 0)\n\t\tself.prereleaseElements = prereleaseElements\n\t\tself.buildElements = buildElements\n\t}\n\n\tinit?(from versionString: String) {\n\t\tdo {\n\t\t\tlet match = versionString.wholeMatch(of: unsafe universalSemVerRegex)! // swiftlint:disable:this force_unwrapping\n\t\t\tself = .init(\n\t\t\t\tcoreIntegers: try match.1.elements.map { coreElement in\n\t\t\t\t\tguard let coreInteger = Integer(coreElement) else {\n\t\t\t\t\t\tthrow MASError.error(coreElement)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn coreInteger\n\t\t\t\t},\n\t\t\t\tprereleaseElements: match.2.elements,\n\t\t\t\tbuildElements: match.3.elements,\n\t\t\t)\n\t\t} catch {\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\nstruct UniversalSemVer: SemVerSyntax {\n\tlet coreElements: [String]\n\tlet prereleaseElements: [String]\n\tlet buildElements: [String]\n\n\tinit(from versionString: String) {\n\t\tlet match = versionString.wholeMatch(of: unsafe universalSemVerRegex)! // swiftlint:disable:this force_unwrapping\n\t\tcoreElements = match.1.elements\n\t\tprereleaseElements = match.2.elements\n\t\tbuildElements = match.3.elements\n\t}\n}\n\nprivate extension BigUInt {\n\tfunc compare(to that: Self) -> ComparisonResult {\n\t\tself < that ? .orderedAscending : self == that ? .orderedSame : .orderedDescending\n\t}\n}\n\nprivate extension FixedWidthInteger {\n\tfunc compare(to that: Self) -> ComparisonResult {\n\t\tself < that ? .orderedAscending : self == that ? .orderedSame : .orderedDescending\n\t}\n}\n\nprivate extension String {\n\tfunc compareSemVerElement(\n\t\tto that: Self,\n\t\toptions mask: CompareOptions = [],\n\t\trange: Range<Self.Index>? = nil,\n\t\tlocale: Locale? = nil,\n\t) -> ComparisonResult {\n\t\tlet selfInteger = BigUInt(self)\n\t\tlet thatInteger = BigUInt(that)\n\t\treturn selfInteger.map { thatInteger.map($0.compare(to:)) ?? .orderedAscending }\n\t\t?? thatInteger.map { _ in .orderedDescending } // swiftformat:disable:this indent\n\t\t?? compare(that, options: mask, range: range, locale: locale) // swiftformat:disable:this indent\n\t}\n}\n\nprivate extension [String] {\n\tfunc compareSemVerElements(to that: Self) -> ComparisonResult {\n\t\tzip(self, that).first { $0 != $1 }.map { $0.compareSemVerElement(to: $1) }\n\t\t?? dropLast { $0 == \"0\" }.count.compare(to: that.dropLast { $0 == \"0\" }.count) // swiftformat:disable:this indent\n\t}\n}\n\nprivate extension Substring? {\n\tvar elements: [String] {\n\t\tmap { $0.split(separator: \".\") }?.map(String.init(_:)) ?? []\n\t}\n}\n\nextension Version {\n\tfunc compareSemVer(to that: Self) -> ComparisonResult {\n\t\tlet coreComparison = coreElements.compareSemVerElements(to: that.coreElements)\n\t\treturn coreComparison == .orderedSame\n\t\t? prereleaseElements.compareSemVerElements(to: that.prereleaseElements) // swiftformat:disable:this indent\n\t\t: coreComparison\n\t}\n\n\tfunc compareSemVerAndBuild(to that: Self) -> ComparisonResult {\n\t\tlet semVerComparison = compareSemVer(to: that)\n\t\treturn semVerComparison == .orderedSame\n\t\t? buildElements.compareSemVerElements(to: that.buildElements) // swiftformat:disable:this indent\n\t\t: semVerComparison\n\t}\n}\n\nprivate nonisolated(unsafe) let universalSemVerRegex = /([^-+]*+)?+(?:-([^+]*+))?+(?:\\+(.*+))?+/\n"
  },
  {
    "path": "Tests/MASTests/Commands/MASTests+Home.swift",
    "content": "//\n// MASTests+Home.swift\n// mas\n//\n// Copyright © 2018 mas-cli. All rights reserved.\n//\n\nprivate import ArgumentParser\n@testable private import mas\ninternal import Testing\n\nprivate extension MASTests {\n\t@Test\n\tfunc `cannot find app home for unknown app ID`() async {\n\t\tlet actual = await consequencesOf(try await MAS.main(try MAS.Home.parse([\"1\"])) { await $0.run(catalogApps: []) })\n\t\tlet expected = Consequences()\n\t\t#expect(actual == expected)\n\t}\n}\n"
  },
  {
    "path": "Tests/MASTests/Commands/MASTests+List.swift",
    "content": "//\n// MASTests+List.swift\n// mas\n//\n// Copyright © 2018 mas-cli. All rights reserved.\n//\n\nprivate import ArgumentParser\n@testable private import mas\ninternal import Testing\n\nprivate extension MASTests {\n\t@Test\n\tfunc `lists apps`() {\n\t\tlet actual = consequencesOf(try MAS.main(try MAS.List.parse([])) { $0.run(installedApps: []) })\n\t\tlet expected = Consequences(\n\t\t\tnil,\n\t\t\t\"\",\n\t\t\t\"\"\"\n\t\t\tWarning: No installed apps found\n\n\t\t\t         If this is unexpected, any of the following command lines should fix things by reindexing apps in\\\n\t\t\t Spotlight (which might take some time):\n\n\t\t\t         # Individual apps (if you know exactly what apps were incorrectly omitted):\n\t\t\t         mdimport /Applications/Example.app\n\n\t\t\t         # All apps (<LargeAppVolume> is the volume optionally selected for large apps):\n\t\t\t         mdimport /Applications /Volumes/<LargeAppVolume>/Applications\n\n\t\t\t         # All file system volumes (if neither aforementioned command solved the issue):\n\t\t\t         sudo mdutil -Eai on\n\n\t\t\t\"\"\",\n\t\t)\n\t\t#expect(actual == expected)\n\t}\n}\n"
  },
  {
    "path": "Tests/MASTests/Commands/MASTests+Lookup.swift",
    "content": "//\n// MASTests+Lookup.swift\n// mas\n//\n// Copyright © 2018 mas-cli. All rights reserved.\n//\n\nprivate import ArgumentParser\n@testable private import mas\ninternal import Testing\n\nprivate extension MASTests {\n\t@Test\n\tfunc `cannot lookup app info for unknown app ID`() {\n\t\tlet actual = consequencesOf(try MAS.main(try MAS.Lookup.parse([\"1\"])) { $0.run(catalogApps: []) })\n\t\tlet expected = Consequences()\n\t\t#expect(actual == expected)\n\t}\n\n\t@Test\n\tfunc `outputs app info`() {\n\t\tlet actual = consequencesOf(\n\t\t\ttry MAS.main(try MAS.Lookup.parse([\"1\"])) { command in\n\t\t\t\tcommand.run(\n\t\t\t\t\tcatalogApps: [\n\t\t\t\t\t\tCatalogApp(\n\t\t\t\t\t\t\tadamID: 1,\n\t\t\t\t\t\t\tappStorePageURLString: \"https://awesome.app\",\n\t\t\t\t\t\t\tfileSizeBytes: \"1000000\",\n\t\t\t\t\t\t\tformattedPrice: \"$2.00\",\n\t\t\t\t\t\t\tminimumOSVersion: \"10.14\",\n\t\t\t\t\t\t\tname: \"Awesome App\",\n\t\t\t\t\t\t\treleaseDate: \"2019-01-07T18:53:13Z\",\n\t\t\t\t\t\t\tsellerName: \"Awesome Dev\",\n\t\t\t\t\t\t\tversion: \"1.0\",\n\t\t\t\t\t\t),\n\t\t\t\t\t],\n\t\t\t\t)\n\t\t\t},\n\t\t)\n\t\tlet expected = Consequences(\n\t\t\tnil,\n\t\t\t\"\"\"\n\t\t\tAwesome App 1.0 [$2.00]\n\t\t\tBy: Awesome Dev\n\t\t\tReleased: 2019-01-07\n\t\t\tMinimum OS: 10.14\n\t\t\tSize: 1 MB\n\t\t\tFrom: https://awesome.app\n\n\t\t\t\"\"\",\n\t\t)\n\t\t#expect(actual == expected)\n\t}\n}\n"
  },
  {
    "path": "Tests/MASTests/Commands/MASTests+Search.swift",
    "content": "//\n// MASTests+Search.swift\n// mas\n//\n// Copyright © 2018 mas-cli. All rights reserved.\n//\n\nprivate import ArgumentParser\n@testable private import mas\ninternal import Testing\n\nprivate extension MASTests {\n\t@Test\n\tfunc `searches for slack`() {\n\t\tlet actual = consequencesOf(\n\t\t\ttry MAS.main(try MAS.Search.parse([\"slack\"])) { command in\n\t\t\t\ttry command.run(catalogApps: [CatalogApp(adamID: 1, name: \"slack\", version: \"0.0\")])\n\t\t\t},\n\t\t)\n\t\tlet expected = Consequences(nil, \"1  slack  (0.0)\\n\")\n\t\t#expect(actual == expected)\n\t}\n\n\t@Test\n\tfunc `cannot search for nonexistent app`() {\n\t\tlet searchTerm = \"nonexistent\"\n\t\tlet actual = consequencesOf(try MAS.main(try MAS.Search.parse([searchTerm])) { try $0.run(catalogApps: []) })\n\t\tlet expected = Consequences(nil, \"\", \"Error: \\(MASError.noCatalogAppsFound(for: searchTerm))\\n\")\n\t\t#expect(actual == expected)\n\t}\n}\n"
  },
  {
    "path": "Tests/MASTests/Commands/MASTests+Seller.swift",
    "content": "//\n// MASTests+Seller.swift\n// mas\n//\n// Copyright © 2019 mas-cli. All rights reserved.\n//\n\nprivate import ArgumentParser\n@testable private import mas\ninternal import Testing\n\nprivate extension MASTests {\n\t@Test\n\tfunc `cannot find seller URL for unknown app ID`() async {\n\t\tlet actual = await consequencesOf(try await MAS.main(try MAS.Seller.parse([\"1\"])) { await $0.run(catalogApps: []) })\n\t\tlet expected = Consequences()\n\t\t#expect(actual == expected)\n\t}\n}\n"
  },
  {
    "path": "Tests/MASTests/Commands/MASTests+Version.swift",
    "content": "//\n// MASTests+Version.swift\n// mas\n//\n// Copyright © 2018 mas-cli. All rights reserved.\n//\n\nprivate import ArgumentParser\n@testable private import mas\ninternal import Testing\n\nprivate extension MASTests {\n\t@Test\n\tfunc `outputs version`() {\n\t\tlet actual = consequencesOf(try MAS.main(try MAS.Version.parse([])))\n\t\tlet expected = Consequences(nil, \"\\(MAS.version)\\n\")\n\t\t#expect(actual == expected)\n\t}\n}\n"
  },
  {
    "path": "Tests/MASTests/Controllers/MASTests+CatalogApp+ITunesSearch.swift",
    "content": "//\n// MASTests+CatalogApp+ITunesSearch.swift\n// mas\n//\n// Copyright © 2019 mas-cli. All rights reserved.\n//\n\nprivate import Foundation\n@testable private import mas\ninternal import Testing\n\nprivate extension MASTests {\n\t@Test\n\tfunc `iTunes searches for slack`() async {\n\t\tlet actual = await consequencesOf(\n\t\t\ttry await search(for: \"slack\") { _ in try (Data(fromResource: \"slack\"), URLResponse()) }.count,\n\t\t)\n\t\tlet expected = Consequences(39)\n\t\t#expect(actual == expected)\n\t}\n\n\t@Test\n\tfunc `looks up slack`() async {\n\t\tlet adamID = 803_453_959 as ADAMID\n\t\tlet actual = await consequencesOf(\n\t\t\ttry await lookup(appID: .adamID(adamID)) { _ in try (Data(fromResource: \"slack-lookup\"), URLResponse()) },\n\t\t)\n\t\t#expect(actual.error == nil && actual.stdout.isEmpty && actual.stderr.isEmpty)\n\t\tguard let catalogApp = actual.value else {\n\t\t\t#expect(actual.value != nil)\n\t\t\treturn\n\t\t}\n\n\t\t#expect(\n\t\t\tcatalogApp.adamID == adamID // swiftformat:disable indent\n\t\t\t&& catalogApp.appStorePageURLString == \"https://apps.apple.com/us/app/slack-for-desktop/id803453959?mt=12\"\n\t\t\t&& catalogApp.name == \"Slack\"\n\t\t\t&& catalogApp.sellerName == \"Slack Technologies, Inc.\"\n\t\t\t&& catalogApp.sellerURLString == \"https://slack.com\"\n\t\t\t&& catalogApp.version == \"3.3.3\",\n\t\t) // swiftformat:enable indent\n\t}\n}\n"
  },
  {
    "path": "Tests/MASTests/Extensions/Data.swift",
    "content": "//\n// Data.swift\n// mas\n//\n// Copyright © 2019 mas-cli. All rights reserved.\n//\n\nprivate import Foundation\n@testable private import mas\n\nextension Data {\n\t/// Unsafe initializer for loading data from string paths.\n\t///\n\t/// - Parameters:\n\t///   - resourcePath: Relative path of resource within subfolderPath\n\t///   - ext: Extension of the resource\n\t///   - subfolderPath: Relative path of folder within the module\n\t/// - Throws: An `Error` if any problem occurs.\n\tinit(\n\t\tfromResource resourcePath: String?,\n\t\twithExtension ext: String? = \"json\",\n\t\tinSubfolderPath subfolderPath: String? = \"\",\n\t) throws {\n\t\tguard\n\t\t\tlet resourceURL = Bundle.module.url(forResource: resourcePath, withExtension: ext, subdirectory: subfolderPath)\n\t\telse {\n\t\t\tthrow MASError.error(\n\t\t\t\t\"\"\"\n\t\t\t\tFailed to find resource\\\n\t\t\t\t\\(resourcePath.map { \" at \\($0)\" } ?? \"\")\\\n\t\t\t\t\\(ext.map { \" with extension \\($0)\" } ?? \"\")\\\n\t\t\t\t\\(subfolderPath.map { \" in subfolder \\($0)\" } ?? \"\")\n\t\t\t\t\"\"\",\n\t\t\t)\n\t\t}\n\n\t\ttry self.init(contentsOf: resourceURL, options: .mappedIfSafe)\n\t}\n}\n"
  },
  {
    "path": "Tests/MASTests/MASTests.swift",
    "content": "//\n// MASTests.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\n@testable private import mas\ninternal import Testing\n\n@Suite(.serialized)\nstruct MASTests {\n\tinit() {\n\t\tMAS.printer.resetErrorCount()\n\t}\n}\n"
  },
  {
    "path": "Tests/MASTests/Models/MASTests+CatalogApp.swift",
    "content": "//\n// MASTests+CatalogApp.swift\n// mas\n//\n// Copyright © 2020 mas-cli. All rights reserved.\n//\n\nprivate import Foundation\n@testable private import mas\ninternal import Testing\n\nprivate extension MASTests {\n\t@Test\n\tfunc `parses catalog app from things that go bump JSON`() {\n\t\tlet actual = consequencesOf(\n\t\t\ttry JSONDecoder().decode(CatalogApp.self, from: .init(fromResource: \"things-lookup\")).adamID,\n\t\t)\n\t\tlet expected = Consequences(1_472_954_003 as ADAMID)\n\t\t#expect(actual == expected)\n\t}\n}\n"
  },
  {
    "path": "Tests/MASTests/Models/MASTests+CatalogAppResults.swift",
    "content": "//\n// MASTests+CatalogAppResults.swift\n// mas\n//\n// Copyright © 2025 mas-cli. All rights reserved.\n//\n\nprivate import Foundation\n@testable private import mas\ninternal import Testing\n\nprivate extension MASTests {\n\t@Test\n\tfunc `parses catalog app results from BBEdit JSON`() {\n\t\tlet actual =\n\t\t\tconsequencesOf(try JSONDecoder().decode(CatalogAppResults.self, from: .init(fromResource: \"bbedit\")).resultCount)\n\t\tlet expected = Consequences(1)\n\t\t#expect(actual == expected)\n\t}\n\n\t@Test\n\tfunc `parses catalog app results from Things JSON`() {\n\t\tlet actual =\n\t\t\tconsequencesOf(try JSONDecoder().decode(CatalogAppResults.self, from: .init(fromResource: \"things\")).resultCount)\n\t\tlet expected = Consequences(12)\n\t\t#expect(actual == expected)\n\t}\n}\n"
  },
  {
    "path": "Tests/MASTests/Resources/bbedit.json",
    "content": "{\n\t\"resultCount\": 1,\n\t\"results\": [\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/d6/4f/1d/d64f1d4d-7317-be28-2622-1c0e0281bf10/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/6c/c3/6e/6cc36e59-bb9d-d1c8-8826-63d6fd9e3190/mzl.khdxvhmp.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/b8/3c/d8/b83cd83c-bb37-7f2b-ac4b-ae2675e6ad4d/mzl.bnkikobm.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple113/v4/6c/f4/4a/6cf44a64-636b-beeb-fa4f-f2c36783a449/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple113/v4/66/f6/44/66f6442b-c49d-179a-c3d3-7e6dde251137/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/9b/7a/52/9b7a5236-b568-3468-244b-81d16191341e/mzl.fhamemzv.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/94/60/02/9460029f-0e79-e5e9-88db-55a11b732c40/mzl.avroidbj.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/df/ef/3b/dfef3b25-1c8d-9671-ae41-3b15ded00137/mzl.mtktnwpr.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/6e/1b/ea/6e1bea82-16be-a75d-21db-9c58db4fb605/mzl.oifmshpk.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple113/v4/d5/47/b4/d547b4ba-bcb7-def3-fefc-e9f50529577e/mzl.ywkwmifv.jpg/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl512\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple114/v4/b9/5d/a8/b95da808-2eea-5edd-0715-b0e13fd43f44/source/512x512bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/bare-bones-software-inc/id396307685?mt=12&uo=4\",\n\t\t\t\"artworkUrl60\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple114/v4/b9/5d/a8/b95da808-2eea-5edd-0715-b0e13fd43f44/source/60x60bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple114/v4/b9/5d/a8/b95da808-2eea-5edd-0715-b0e13fd43f44/source/100x100bb.png\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 404009241,\n\t\t\t\"trackName\": \"BBEdit\",\n\t\t\t\"primaryGenreName\": \"Developer Tools\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6026\",\n\t\t\t\t\"6007\"\n\t\t\t],\n\t\t\t\"minimumOsVersion\": \"10.14\",\n\t\t\t\"releaseNotes\": \"BBEdit 13.1.3 is a recommended update for all customers. This version includes an assortment of fixes for customer-reported issues, including a bug which caused the Search menu to display incorrect information or crash the application when pulled down. The full change notes are too long to include in the space allowed, but are available via the \\\"Support\\\" link on BBEdit's page in the App Store app.\\n\\nBBEdit 13.1 introduced significant feature additions and refinements, including (but not limited to): improved HTML previewing; advanced control over Markdown rendering; a new “Run Unix Command” command; significant improvements to its built-in CSS syntax coloring and navigation support; and built-in HTML Tidy commands.\",\n\t\t\t\"releaseDate\": \"2011-01-05T08:23:40Z\",\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"15198547\",\n\t\t\t\"sellerUrl\": \"https://www.barebones.com/products/bbedit/\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-07-30T12:53:37Z\",\n\t\t\t\"trackCensoredName\": \"BBEdit\",\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/bbedit/id404009241?mt=12&uo=4\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"version\": \"13.1.3\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"primaryGenreId\": 6026,\n\t\t\t\"artistId\": 396307685,\n\t\t\t\"artistName\": \"Bare Bones Software, Inc.\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Developer Tools\",\n\t\t\t\t\"Productivity\"\n\t\t\t],\n\t\t\t\"price\": 0.00,\n\t\t\t\"description\": \"BBEdit is the leading professional text, code, and markup editor for the Macintosh. \\n\\nAs the \\\"go to\\\" tool for web site designers, web application developers, writers, and software developers, this award-winning product provides an abundance of high-performance features for editing, searching, and manipulation of text, code, and HTML/XML markup.\\n\\nAs a replacement for TextWrangler, BBEdit is built by the same developers, using the same award-winning technology, and is identical to TextWrangler in every way you're used to. BBEdit is 64-bit and compatible with macOS Catalina.\\n\\nAn intelligent interface provides easy access to BBEdit’s best-of-class features, including: grep pattern matching; search and replace across multiple files; project definition tools; function navigation and syntax coloring for numerous source code languages; code folding; FTP and SFTP open and save; AppleScript and Automator support; Unix scripting support; text and code completion; a complete set of robust HTML tools; and more.\\n\\nBBEdit offers a 30-day evaluation period (beginning the first time you use it on your computer), during which its full feature set is available.\\n\\nDuring the evaluation period, BBEdit is fully functional. After the evaluation period has expired, you can continue to use BBEdit for free, forever, with no nag screens or unsolicited interruptions.\\n\\nIn “free mode”, BBEdit provides a modified set of features, which incorporates a powerful set of core features. Using BBEdit in free mode costs you nothing, while providing an upgrade path to advanced features and capabilities.\\n\\nTo enable BBEdit’s advanced features after the evaluation period is over, you will need to have an active BBEdit subscription. Subscriptions are available on either a monthly or annual basis.\\n\\nAn active subscription gives you access to all of BBEdit’s advanced features, including any new features that we introduce during updates or major upgrades, for as long as the subscription is in good standing.\\n\\nPlease see our comparison chart for a detailed listing of which advanced features are available with a subscription.\\n\\nSubscription terms and conditions:\\n\\nWe do not collect any data from your use of BBEdit, whether or not a subscription is in effect.\\n\\nYour interactions with BBEdit and with Bare Bones Software, Inc. are protected by our privacy policy.\\n\\nYour use of BBEdit is governed by the terms of its end-user license.\\n\\nWhen you purchase a subscription, payment will be charged to your iTunes Account upon confirmation of purchase.\\n\\nYour subscription will renew automatically, unless you cancel your subscription at least 24 hours prior to the end of the currently active subscription period. Your iTunes Account will be charged for the renewal within 24 hours prior to the end of the currently active subscription period, and your account history will reflect the cost of the renewal.\\n\\nYou can manage your subscription and cancel automatic renewal by going to your \\\"Manage my Subscriptions\\\" page after purchase.\\n\\nPurchasing a subscription will permanently end your evaluation period, and forfeits any unused portion of the evaluation period, if applicable.\\n\\nFor the full text of the BBEdit end user license for Mac App Store customers, please visit this page on our web site: https://www.barebones.com/products/bbedit/appstore/terms.html\",\n\t\t\t\"sellerName\": \"Bare Bones Software, Inc.\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"bundleId\": \"com.barebones.bbedit\",\n\t\t\t\"userRatingCount\": 0\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "Tests/MASTests/Resources/slack-lookup.json",
    "content": "{\n\t\"resultCount\": 1,\n\t\"results\": [\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple118/v4/8d/07/74/8d0774c5-90aa-611c-3701-35f6158fb77e/source/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple128/v4/6d/86/a7/6d86a74d-5c45-1a61-7828-ff3251360271/source/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple118/v4/18/c1/38/18c138de-5bf2-586b-34de-c81e05568ea3/source/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple118/v4/4a/92/50/4a925081-61d0-ff32-eb2a-4b57db03aaab/source/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple128/v4/84/94/74/84947420-25dc-35e2-2761-9fa2b583c0a5/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple128/v4/84/94/74/84947420-25dc-35e2-2761-9fa2b583c0a5/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple128/v4/84/94/74/84947420-25dc-35e2-2761-9fa2b583c0a5/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://itunes.apple.com/us/developer/slack-technologies-inc/id453420243?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 4,\n\t\t\t\"trackCensoredName\": \"Slack\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\",\n\t\t\t\t\"FR\",\n\t\t\t\t\"DE\",\n\t\t\t\t\"JA\",\n\t\t\t\t\"ES\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"74398324\",\n\t\t\t\"sellerUrl\": \"https://slack.com\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"userRatingCountForCurrentVersion\": 106,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/slack-for-desktop/id803453959?mt=12\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"releaseNotes\": \"All updates are important, of course. This one contains security updates, and as we know, they’re the most important kind of all.\",\n\t\t\t\"currentVersionReleaseDate\": \"2018-10-02T23:28:05Z\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"sellerName\": \"Slack Technologies, Inc.\",\n\t\t\t\"primaryGenreId\": 12001,\n\t\t\t\"primaryGenreName\": \"Business\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"12001\",\n\t\t\t\t\"12014\"\n\t\t\t],\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"version\": \"3.3.3\",\n\t\t\t\"releaseDate\": \"2014-01-23T02:46:20Z\",\n\t\t\t\"minimumOsVersion\": \"10.9\",\n\t\t\t\"artistId\": 453420243,\n\t\t\t\"artistName\": \"Slack Technologies, Inc.\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Business\",\n\t\t\t\t\"Productivity\"\n\t\t\t],\n\t\t\t\"price\": 0,\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"description\": \"Slack brings team communication and collaboration into one place so you can get more work done, whether you belong to a large enterprise or a small business. Check off your to-do list and move your projects forward by bringing the right people, conversations, tools, and information you need together. Slack is available on any device, so you can find and access your team and your work, whether you’re at your desk or on the go.\\n\\nUse Slack to: \\n• Communicate with your team and organize your conversations by topics, projects, or anything else that matters to your work\\n• Message or call any person or group within your team\\n• Share and edit documents and collaborate with the right people all in Slack \\n• Integrate into your workflow, the tools and services you already use including Google Drive, Salesforce, Dropbox, Asana, Twitter, Zendesk, and more\\n• Easily search a central knowledge base that automatically indexes and archives your team’s past conversations and files\\n• Customize your notifications so you stay focused on what matters\\n\\nScientifically proven (or at least rumored) to make your working life simpler, more pleasant, and more productive. We hope you’ll give Slack a try.\\n\\nStop by and learn more at: https://slack.com/\",\n\t\t\t\"bundleId\": \"com.tinyspeck.slackmacgap\",\n\t\t\t\"trackId\": 803453959,\n\t\t\t\"trackName\": \"Slack\",\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"userRatingCount\": 1467,\n\t\t\t\"averageUserRating\": 4\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "Tests/MASTests/Resources/slack.json",
    "content": "{\n\t\"resultCount\": 39,\n\t\"results\": [\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/b6/96/82/b6968256-1ba7-017a-0027-58b8ba76af25/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/48/be/b8/48beb83d-91db-e956-edcd-ba44e5639a40/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/f5/bd/86/f5bd862a-ff6b-b1f7-d7da-149d7de82614/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple123/v4/7a/75/8b/7a758b1c-7359-26fb-e5d2-1b7971589321/pr_source.jpg/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple114/v4/1d/d5/9d/1dd59dc1-8537-9471-d617-f0c4d80be440/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple114/v4/1d/d5/9d/1dd59dc1-8537-9471-d617-f0c4d80be440/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple114/v4/1d/d5/9d/1dd59dc1-8537-9471-d617-f0c4d80be440/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/slack-technologies-inc/id453420243?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 803453959,\n\t\t\t\"trackName\": \"Slack\",\n\t\t\t\"releaseDate\": \"2014-01-23T02:46:20Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6000\",\n\t\t\t\t\"6007\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.10\",\n\t\t\t\"primaryGenreName\": \"Business\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-08-07T16:58:01Z\",\n\t\t\t\"releaseNotes\": \"Bug Fixes\\n• In rare cases, Slack would simply fail to start altogether. While we’re sure we could all use a coffee break, we know you could also use an application that runs. So we fixed that.\\n• We made the screen you see when you have connection problems more useful. We also spruced it up a bit with a fresh coat of paint.\\n• Our notifications system sprung a leak, so we brought it in for a tune-up. Everything should be running smoother now.\",\n\t\t\t\"primaryGenreId\": 6000,\n\t\t\t\"sellerName\": \"Slack Technologies, Inc.\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Slack\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\",\n\t\t\t\t\"FR\",\n\t\t\t\t\"DE\",\n\t\t\t\t\"JA\",\n\t\t\t\t\"PT\",\n\t\t\t\t\"ES\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"80596748\",\n\t\t\t\"sellerUrl\": \"https://slack.com\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/slack/id803453959?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Slack brings team communication and collaboration into one place so you can get more work done, whether you belong to a large enterprise or a small business. Check off your to-do list and move your projects forward by bringing the right people, conversations, tools, and information you need together. Slack is available on any device, so you can find and access your team and your work, whether you’re at your desk or on the go.\\n\\nUse Slack to: \\n• Communicate with your team and organize your conversations by topics, projects, or anything else that matters to your work\\n• Message or call any person or group within your team\\n• Share and edit documents and collaborate with the right people all in Slack \\n• Integrate into your workflow, the tools and services you already use including Google Drive, Salesforce, Dropbox, Asana, Twitter, Zendesk, and more\\n• Easily search a central knowledge base that automatically indexes and archives your team’s past conversations and files\\n• Customize your notifications so you stay focused on what matters\\n\\nScientifically proven (or at least rumored) to make your working life simpler, more pleasant, and more productive. We hope you’ll give Slack a try.\\n\\nStop by and learn more at: https://slack.com/\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Business\",\n\t\t\t\t\"Productivity\"\n\t\t\t],\n\t\t\t\"artistId\": 453420243,\n\t\t\t\"artistName\": \"Slack Technologies, Inc.\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.tinyspeck.slackmacgap\",\n\t\t\t\"version\": \"4.8.0\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple123/v4/59/9f/b0/599fb00a-794b-2e98-4f8a-8c97e338bed7/mzl.oyxmnyla.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple113/v4/7f/19/48/7f194831-3555-3def-ae86-a2c77966a12f/mzl.zfzeegwv.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/df/3e/d6/df3ed640-c00f-9b7e-577e-4eea3a36fc94/mzl.ldwdcyjg.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/28/b0/89/28b089ac-da7b-3cd4-66ea-a15dad33a52a/mzl.kbgzprvj.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/fd/3e/8e/fd3e8e76-ec96-c24a-3617-c6e5dd58fe14/mzl.slrwmdjl.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/c8/8c/0e/c88c0e70-cd58-a5fb-a222-35964b660627/mzl.wtqirxur.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/14/a9/20/14a920a6-836e-8213-4557-ed45f2f44042/mzl.keqdwues.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/26/38/45/2638454f-1887-639c-750e-9c6d60d9b9c1/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/03/2b/f6/032bf675-9f4e-1c8f-422b-27a13f1905e4/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple123/v4/81/86/1f/81861f8c-689a-fd6a-79c0-277817e0b7f2/mzl.zdmmurjb.jpg/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple114/v4/99/82/0b/99820b2f-94cb-c950-ae6d-7f0c2398570c/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple114/v4/99/82/0b/99820b2f-94cb-c950-ae6d-7f0c2398570c/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple114/v4/99/82/0b/99820b2f-94cb-c950-ae6d-7f0c2398570c/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/readdle-inc/id285035419?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1176895641,\n\t\t\t\"trackName\": \"Spark – Email App by Readdle\",\n\t\t\t\"releaseDate\": \"2016-11-30T18:24:05Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6007\",\n\t\t\t\t\"6002\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.13\",\n\t\t\t\"primaryGenreName\": \"Productivity\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-09-02T11:52:29Z\",\n\t\t\t\"releaseNotes\": \"Today's update improves Spark's experience with Microsoft 365 and contains a small fix for the issue with the cursor in the 'say something' field. \\n\\nIf you feel generous and have a couple of minutes, please leave your review. It makes a difference to us. Thank you in advance. :) \\nAnd if you need us you can find us at support@sparkmailapp.com\",\n\t\t\t\"primaryGenreId\": 6007,\n\t\t\t\"sellerName\": \"Readdle Inc.\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Spark – Email App by Readdle\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\",\n\t\t\t\t\"FR\",\n\t\t\t\t\"DE\",\n\t\t\t\t\"IT\",\n\t\t\t\t\"JA\",\n\t\t\t\t\"PT\",\n\t\t\t\t\"RU\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"ES\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"50692261\",\n\t\t\t\"sellerUrl\": \"https://sparkmailapp.com\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/spark-email-app-by-readdle/id1176895641?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Spark is the best personal email client and a revolutionary email for teams. You will love your email again! \\n\\n\\\"Best of the App Store\\\" - Apple\\n\\\"It's a combination of polish, simplicity, and depth\\\" - FastCompany\\n\\\"You can create an email experience that works for you\\\" - TechCrunch\\n\\n**Beautiful and Intelligent Email App**\\nWe are building the future of email. Modern design, fast, intuitive, collaborative, seeing what’s important, automation and truly personal experience that you love - this is what Spark stands for.\\n\\n**Farewell to Busy Inbox**\\nSmart Inbox lets you quickly see what's important in your inbox and clean up the rest. All new emails are smartly categorized into Personal, Notifications and Newsletters.\\n\\n**Discuss email privately**\\nInvite teammates to discuss specific emails and threads. Ask questions, get answers, and keep everyone in the loop.\\n\\n**Create email together**\\nFor the first time ever, collaborate with your teammates using real-time editor to compose professional emails.\\n\\n**Schedule emails to be sent later**\\nSchedule emails to be sent when your recipient is most likely to read them. It works even if your device is turned off.\\n\\n**Snooze That One For Later**\\nSnooze an email and get back to it when the time is right. Snoozing works across all your Apple devices.\\n\\n**Find Any Email In An Instant**\\nPowerful, natural language search makes it easy to find that email you're looking for. Just search the way you think and let Spark do the rest.\\n\\n**Get Notified About Important Emails Only**\\nSmart Notifications filter out the noise, letting you know when an email is important, saving you from notification overload.\\n\\n**Powerful Integrations**\\nIntegrate Spark into your workflow and take productivity to the next level. Supports Dropbox, Box, iCloud Drive, and more.\\n\\n**Built-in calendar**\\nA full-featured calendar works right in your email to help you always be on top of your schedule. Create events easily using natural language.\\n\\n**Create links to email**\\nCreate secure links to a specific email or conversation. Share the link on Slack, Skype, CRM, or any other medium so your team can see it and collaborate around it.\\n\\n**Sign Off With A Swipe**\\nBefore you send an email, quickly swipe to choose the right signature for the occasion.\\n\\n**Email with Emotion**\\nQuick Replies get the point across with just a tap. Love, like or acknowledge an email in an instant.\\n\\n**Email Never Looked This Good**\\nThat terrible mess in your inbox is now replaced it with a beautiful, threaded message design.\\n\\n**A Truly Personal Experience**\\nCustomize Spark to work as you do. You decide which swipes do what, what cards are shown, and how many emails you want to see.\\nYou’ll love your email again!\\n \\nIf you need us, you can always find us at rdsupport@readdle.com\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Productivity\",\n\t\t\t\t\"Utilities\"\n\t\t\t],\n\t\t\t\"artistId\": 285035419,\n\t\t\t\"artistName\": \"Readdle Inc.\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.readdle.smartemail-Mac\",\n\t\t\t\"version\": \"2.8.3\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple111/v4/8c/8b/f8/8c8bf8af-a7ef-eebf-3359-bfca1c8ab7d6/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple91/v4/e2/a4/23/e2a42353-e964-59dd-f578-6eaf7e6db808/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is2-ssl.mzstatic.com/image/thumb/Purple62/v4/6b/cf/1e/6bcf1e4b-4c74-35d4-c626-9207dfe3ff7f/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is2-ssl.mzstatic.com/image/thumb/Purple62/v4/6b/cf/1e/6bcf1e4b-4c74-35d4-c626-9207dfe3ff7f/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is2-ssl.mzstatic.com/image/thumb/Purple62/v4/6b/cf/1e/6bcf1e4b-4c74-35d4-c626-9207dfe3ff7f/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/tenor/id917932199?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1043270657,\n\t\t\t\"trackName\": \"GIF Keyboard\",\n\t\t\t\"releaseDate\": \"2015-10-29T04:29:03Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6002\",\n\t\t\t\t\"6005\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.11\",\n\t\t\t\"primaryGenreName\": \"Utilities\",\n\t\t\t\"currentVersionReleaseDate\": \"2018-03-17T21:10:03Z\",\n\t\t\t\"releaseNotes\": \"- We've updated our Terms of Service and Privacy Policy. If you have a Tenor account, please make sure to accept the new terms.\\n- Tenor GIF Keyboard has been optimized -- the app should now run more smoothly than ever.\",\n\t\t\t\"primaryGenreId\": 6002,\n\t\t\t\"sellerName\": \"Tenor, Inc.\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"GIF Keyboard\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"4774516\",\n\t\t\t\"sellerUrl\": \"https://tenor.com\",\n\t\t\t\"contentAdvisoryRating\": \"17+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/gif-keyboard/id1043270657?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"17+\",\n\t\t\t\"description\": \"Sometimes emojis just don’t cut it. Share your true feelings with GIFs.\\n\\nDrag and drop GIFs from your menubar directly into iMessage, and collect your favorite GIFs from anywhere by dropping GIFs into your menubar.\\n\\nIt’s perfect for all those times you wanted to...\\n\\n- Express just how much you love pizza.\\n- Annoy your friends with that one lyric you just can’t stop singing.\\n- Tell your crush that cuddling should be in your future. \\n\\n\\nTenor GIF for Mac Features:\\n\\n* Always send the perfect GIF and video responses to your best friends straight from your menubar! \\n\\n* Browse through categories like reactions, music, trending and more. \\n\\n* Search millions of GIFs and videos on Tenor for the perfect moment. You can also tap the emoji icon in the menu to search by your favorite emoji!\\n\\n* See a GIF you like while browsing the web or receive a GIF from a friend? Drag/Drop the GIF to your Menubar to save for later. That means no saving to clunky desktop folders, and its instantly available from your toolbar\\n\\n* Works with your favorite messengers and social networks including iMessage, Slack, Email, Telegram, Facebook, and Reddit\\n\\n* Syncs with Tenor GIF Keyboard on your iPhone. Your GIF collections are instantly available on both your iPhone and Mac so your favorites GIFs are accessible everywhere\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Utilities\",\n\t\t\t\t\"Social Networking\"\n\t\t\t],\n\t\t\t\"artistId\": 917932199,\n\t\t\t\"artistName\": \"Tenor\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.riffsy.GIF-for-Mac\",\n\t\t\t\"version\": \"2.0.5\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple115/v4/dd/20/f0/dd20f0d6-79d5-3fcc-5a09-fe8a110cdc16/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple115/v4/58/1d/cb/581dcbf0-9709-1efd-cdd2-b7bb065680ae/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple125/v4/b4/36/3c/b4363cd8-2a99-4d0c-6c50-e54fae209938/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple125/v4/ef/63/79/ef63795c-1dea-c772-b5e3-3a2d4dfadfc9/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple115/v4/fc/0c/66/fc0c66b9-4c1c-d08b-dfdb-62f3e10710a5/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/4e/a2/52/4ea25263-c63c-5073-8f3c-c907bbe7b332/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/4e/a2/52/4ea25263-c63c-5073-8f3c-c907bbe7b332/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/4e/a2/52/4ea25263-c63c-5073-8f3c-c907bbe7b332/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/moxtra-inc/id551221476?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 991215717,\n\t\t\t\"trackName\": \"Moxtra: Business Collaboration\",\n\t\t\t\"releaseDate\": \"2015-05-13T01:51:40Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6000\",\n\t\t\t\t\"6007\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.8\",\n\t\t\t\"primaryGenreName\": \"Business\",\n\t\t\t\"currentVersionReleaseDate\": \"2019-03-20T23:26:06Z\",\n\t\t\t\"releaseNotes\": \"- Fixed bugs\",\n\t\t\t\"primaryGenreId\": 6000,\n\t\t\t\"sellerName\": \"Moxtra, Inc.\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Moxtra: Business Collaboration\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"DA\",\n\t\t\t\t\"NL\",\n\t\t\t\t\"EN\",\n\t\t\t\t\"FI\",\n\t\t\t\t\"FR\",\n\t\t\t\t\"DE\",\n\t\t\t\t\"ID\",\n\t\t\t\t\"IT\",\n\t\t\t\t\"JA\",\n\t\t\t\t\"KO\",\n\t\t\t\t\"PT\",\n\t\t\t\t\"RU\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"ES\",\n\t\t\t\t\"SV\",\n\t\t\t\t\"TH\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"TR\",\n\t\t\t\t\"VI\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"13535823\",\n\t\t\t\"sellerUrl\": \"https://www.moxo.com\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/moxtra-business-collaboration/id991215717?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Moxtra: Accelerating business in the mobile world.\\n\\nMoxtra is a collaboration solution built to accelerate business. Present, secure feedback, get approvals on content to close business while on the go. Collaborate on documents and content across teams, with customers, partners, and colleagues. Recreate the power of face-to-face meetings with secure messaging, robust document collaboration, video conferencing, electronic signature, and more – in context. Moxtra is an secure, enterprise class service available as a white-label, private cloud, or on-premise solution.\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Business\",\n\t\t\t\t\"Productivity\"\n\t\t\t],\n\t\t\t\"artistId\": 551221476,\n\t\t\t\"artistName\": \"Moxtra, Inc.\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.moxtra.desktop\",\n\t\t\t\"version\": \"6.0.7\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple113/v4/9e/fd/73/9efd7364-ffaf-5e20-e1b4-59b036f97cd9/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple123/v4/a9/8c/4b/a98c4be2-9027-1006-6528-c5dfe1ed885d/mzl.ltakrafq.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/80/e9/f2/80e9f22e-d740-363f-1830-d318f2200984/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/80/e9/f2/80e9f22e-d740-363f-1830-d318f2200984/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/80/e9/f2/80e9f22e-d740-363f-1830-d318f2200984/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/henrik-wenz/id1456462086?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1456462087,\n\t\t\t\"trackName\": \"All-in-One Messenger\",\n\t\t\t\"releaseDate\": \"2019-03-28T00:50:45Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6007\",\n\t\t\t\t\"6005\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.10.0\",\n\t\t\t\"primaryGenreName\": \"Productivity\",\n\t\t\t\"currentVersionReleaseDate\": \"2019-04-09T02:15:29Z\",\n\t\t\t\"releaseNotes\": \"- Frameless window \\n- Better design\\n- Fixed messenger load bug\\n- Use custom protocol (improve security)\",\n\t\t\t\"primaryGenreId\": 6007,\n\t\t\t\"sellerName\": \"Henrik Wenz\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"All-in-One Messenger\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"AM\",\n\t\t\t\t\"AR\",\n\t\t\t\t\"BN\",\n\t\t\t\t\"BG\",\n\t\t\t\t\"CA\",\n\t\t\t\t\"HR\",\n\t\t\t\t\"CS\",\n\t\t\t\t\"DA\",\n\t\t\t\t\"NL\",\n\t\t\t\t\"EN\",\n\t\t\t\t\"ET\",\n\t\t\t\t\"FI\",\n\t\t\t\t\"FR\",\n\t\t\t\t\"DE\",\n\t\t\t\t\"EL\",\n\t\t\t\t\"GU\",\n\t\t\t\t\"HE\",\n\t\t\t\t\"HI\",\n\t\t\t\t\"HU\",\n\t\t\t\t\"ID\",\n\t\t\t\t\"IT\",\n\t\t\t\t\"JA\",\n\t\t\t\t\"KN\",\n\t\t\t\t\"KO\",\n\t\t\t\t\"LV\",\n\t\t\t\t\"LT\",\n\t\t\t\t\"MS\",\n\t\t\t\t\"ML\",\n\t\t\t\t\"MR\",\n\t\t\t\t\"NB\",\n\t\t\t\t\"FA\",\n\t\t\t\t\"PL\",\n\t\t\t\t\"PT\",\n\t\t\t\t\"RO\",\n\t\t\t\t\"RU\",\n\t\t\t\t\"SR\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"SK\",\n\t\t\t\t\"SL\",\n\t\t\t\t\"ES\",\n\t\t\t\t\"SW\",\n\t\t\t\t\"SV\",\n\t\t\t\t\"TA\",\n\t\t\t\t\"TE\",\n\t\t\t\t\"TH\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"TR\",\n\t\t\t\t\"UK\",\n\t\t\t\t\"VI\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"59177570\",\n\t\t\t\"sellerUrl\": \"https://allinone.im/\",\n\t\t\t\"contentAdvisoryRating\": \"17+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/all-in-one-messenger/id1456462087?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"17+\",\n\t\t\t\"description\": \"Use messengers like WhatsApp, Telegram, Messenger, Skype and many more in one app.\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Productivity\",\n\t\t\t\t\"Social Networking\"\n\t\t\t],\n\t\t\t\"artistId\": 1456462086,\n\t\t\t\"artistName\": \"Henrik Wenz\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"im.allinone.messenger\",\n\t\t\t\"version\": \"0.3.1\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple113/v4/7d/31/f4/7d31f44c-5094-b4c8-d630-f218f493058c/mzl.jkthnpaz.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/b3/61/d9/b361d9f7-881e-3692-aac2-b28be0a30ae1/mzl.eznpdmta.png/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple123/v4/d7/3b/96/d73b96f0-2c4e-0802-d46a-f30b73db8f2e/mzl.xafzbvqs.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/41/ee/eb/41eeebe8-f759-d786-a952-098d251a3274/mzl.pzxvxjgw.png/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple113/v4/a3/9a/fe/a39afe75-0d3f-6445-3c5e-373653a174c8/mzl.lcubnpym.png/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple123/v4/f1/f4/2d/f1f42ded-7f57-dffc-961d-5cdde8ea3f7f/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple123/v4/6e/20/de/6e20de36-06ea-8f38-777d-9b37e6877859/mzl.ydczebqy.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/84/a2/81/84a28150-6acf-171d-fd2d-a4581e94ba2c/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/84/a2/81/84a28150-6acf-171d-fd2d-a4581e94ba2c/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/84/a2/81/84a28150-6acf-171d-fd2d-a4581e94ba2c/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/riva-fzc/id503815096?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 883594849,\n\t\t\t\"trackName\": \"Flock: Team Communication App\",\n\t\t\t\"releaseDate\": \"2014-06-05T23:27:57Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6000\",\n\t\t\t\t\"6007\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.10.0\",\n\t\t\t\"primaryGenreName\": \"Business\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-05-18T12:00:43Z\",\n\t\t\t\"releaseNotes\": \"We've added animated stickers! \\nWe also squashed some bugs and improved overall performance of the app!\\n\\nFlock as you were!\",\n\t\t\t\"primaryGenreId\": 6000,\n\t\t\t\"sellerName\": \"RIVA FZC\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Flock: Team Communication App\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"84779228\",\n\t\t\t\"sellerUrl\": \"https://flock.com\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/flock-team-communication-app/id883594849?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Flock is a powerful business messaging and team collaboration app that brings all your work in one place. \\n\\nToday, your team’s communication is scattered across emails, meetings, and multiple tools. With Flock you can quickly bring people together, discuss ideas, share information, assign tasks and track team progress, so your team can focus on what they do best. Whether you are a large enterprise, a small business or a high-growth startup, Flock effortlessly adapts to your unique needs. \\n\\nOver 32,000 organizations love Flock and here’s why you might find it useful too:\\n• Team communication made easy through 1-1 chats and group messaging\\n• Organize conversations into different channels for projects, departments or topics\\n• Find information and share files on-the-go\\n• Enjoy video & audio calling along with free screen sharing capabilities\\n• Do more with free built-in productivity tools such as to-do’s, reminders and polls\\n• Integrates with all your favourite tools and services that you already use including Google \\n   Drive, Trello, Jira, GitHub, Hubspot, etc.\\n• Effortlessly find information that was discussed in a 1-1/team chat using Search \\n• Flock is private, safe and secure (We are SOC2 and GDPR compliant)\\n\\nFlock is free to use for as many users and for as long as you want. You can upgrade to our paid plans for enhanced features and increased user control.\\n\\nRecommended by experts:\\n• Gartner Cool Vendor 2018\\n• G2 Crowd Leader Spring 2018 \\n• #1 Slack Alternative by PCMag \\n• Top rated alternative for Slack by ProductHunt\\n\\nYou’re in good company.\\n- Tim Hortons\\n- Avendus\\n- Gini and Jony\\n- Ricoh\\n- Victorinox\\n\\nAnd here’s what our happy users have to say about Flock:\\n\\n“I can’t say enough kind things about Flock. Moved the team to it from Slack and couldn’t be happier.”\\n- Luke Rodriguez, Modern Horrors\\n\\n“Flock is convenient and real time and is making communication seamless and easy. My entire team today is on Flock.”\\n- Prashant Tandon, CEO and Co-Founder, 1MG\\n\\n“Flock has become the way our Sales Team communicates. It's fast, reliable, fun and easy to use.”\\n- Bryan Morales, CIB Corporation\\n\\nFollow us on Facebook and Twitter @flock\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Business\",\n\t\t\t\t\"Productivity\"\n\t\t\t],\n\t\t\t\"artistId\": 503815096,\n\t\t\t\"artistName\": \"RIVA FZC\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"to.go.osx\",\n\t\t\t\"version\": \"2.2.388\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple114/v4/40/d6/69/40d6695a-6d55-a6af-2c5a-918baf218ec9/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple124/v4/cd/1f/5e/cd1f5ef8-b7d9-c5da-3280-45c703d89ec8/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple124/v4/17/44/1c/17441c02-37d6-d3f6-420b-da5114df9c45/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple124/v4/6e/05/37/6e0537aa-3438-6bfe-d7d2-e02d30ee8d34/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple124/v4/b6/24/cd/b624cd52-2079-5118-bea8-94f7fa31a467/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple124/v4/e1/0b/8d/e10b8d63-660a-2828-3ecb-eb7a197b62fb/mzl.umozqbal.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple114/v4/96/76/38/96763896-f145-a59b-8bd0-934a7dbce2a3/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple114/v4/96/76/38/96763896-f145-a59b-8bd0-934a7dbce2a3/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple114/v4/96/76/38/96763896-f145-a59b-8bd0-934a7dbce2a3/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/bloop-s-r-l/id389546852?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 918858936,\n\t\t\t\"trackName\": \"Airmail 4\",\n\t\t\t\"releaseDate\": \"2014-10-16T20:48:01Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6007\",\n\t\t\t\t\"6002\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.12\",\n\t\t\t\"primaryGenreName\": \"Productivity\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-08-04T22:49:54Z\",\n\t\t\t\"releaseNotes\": \"- Bugfix\",\n\t\t\t\"primaryGenreId\": 6007,\n\t\t\t\"sellerName\": \"Bloop S.R.L\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Airmail 4\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"AR\",\n\t\t\t\t\"MY\",\n\t\t\t\t\"CA\",\n\t\t\t\t\"CS\",\n\t\t\t\t\"DA\",\n\t\t\t\t\"NL\",\n\t\t\t\t\"EN\",\n\t\t\t\t\"FI\",\n\t\t\t\t\"FR\",\n\t\t\t\t\"GL\",\n\t\t\t\t\"DE\",\n\t\t\t\t\"EL\",\n\t\t\t\t\"HE\",\n\t\t\t\t\"HU\",\n\t\t\t\t\"IT\",\n\t\t\t\t\"JA\",\n\t\t\t\t\"KO\",\n\t\t\t\t\"NB\",\n\t\t\t\t\"NN\",\n\t\t\t\t\"PL\",\n\t\t\t\t\"PT\",\n\t\t\t\t\"RO\",\n\t\t\t\t\"RU\",\n\t\t\t\t\"SR\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"SK\",\n\t\t\t\t\"ES\",\n\t\t\t\t\"SV\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"TR\",\n\t\t\t\t\"UK\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"62121809\",\n\t\t\t\"sellerUrl\": \"https://airmailapp.com\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/airmail-4/id918858936?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"*** Apple Design Award 2017 Winner ***\\n\\nAirmail is a mail client designed with performance and intuitive interaction in mind optimized for macOS and iOS!\\n\\nSupport for iCloud™, MS Exchange, Gmail™, Google™ Apps,  IMAP, POP3, Yahoo!™, AOL™, Outlook.com™, Live.com™\\n\\nAirmail was designed from the ground UP to retain the same experience with a single or multiple accounts and provide a quick, modern user experience. Airmail is clean and allows you to get to your emails without interruption - it's the mail client for the 21st century. \\n\\nWe have taken usability and function to the next level with Airmail and bring a striking-design with support for all major email services. Switch between accounts like a breeze and quick reply to incoming messages within seconds - email has never been so easy and productive. \\n\\n- iCloud Account sync\\n- Handoff support \\n- Today Extension, quick access to your inbox.\\n- Action Extension, Airmail Compose, Airmail Share.\\n\\nAccounting:\\n- Unified Inbox\\n- Alias with custom SMTP\\n- Exchange, iCloud™, Gmail™, IMAP, POP3, Google™ Apps, Yahoo!™, AOL™, Outlook.com™, Live.com™\\n- Local Accounts\\n- Import from Apple Mail, MBOX archive, EML, EMLX\\n\\nInteractions:\\n- Quick Reply\\n- Offline operations\\n- Move messages on Different mailboxes\\n- Multi Touch gestures\\n\\nShortcuts:\\n- Gmail Shortcuts\\n- Custom global shortcuts\\n- Quick Label, Move, Label and Archive\\n- Quick folder selection\\n\\nConversations:\\n- Group by id\\n- Group by subject\\n- Chronological Reverse \\n- Muted CC’d conversation\\n\\nVisual:\\n- Multiple visual themes\\n- Minimal and extended Mode\\n- Plain Text Rendering\\n\\nNotifications:\\n- Per account notifications\\n- Notification center support\\n- Notification alerts with custom actions\\n\\nAddress:\\n- Gmail, Exchange and OS X contacts\\n- Contacts Group\\n- Filter by address\\n- Open Directory search\\n\\nComposer:\\n- Exchange Global Address List\\n- Markdown, Html(Html Source for templates), and text only.\\n- Bullet and numbered list.\\n\\nSending:\\n- Auto CC, BCC.\\n- Send Delay\\n- Redirect\\n- Send again \\n- Bounce\\n\\nAdvanced:\\n- EML Import/Export\\n- Applescript\\n\\nSignatures:\\n- Multiple Account Signatures\\n- Markdown, Rich text, Html Source, and text only.\\n- Signature above or below the quote\\n\\nSearch & Filtering:\\n- Global search for multiple accounts\\n- Realtime powerful filters\\n- Sort messages, Date, Attachments, Conversations ....\\n- Show messages of the same user\\n- Flags and filters\\n\\nFolders, Labels:\\n- Nested folders\\n- Create, Delete and edit folders\\n- Custom colors synced by iCloud\\n- Custom folder mappings\\n- ToDo, Done, Memo\\n\\nSend to:\\n- Omnifocus\\n- Fantastical\\n- Evernote\\n- Apple Reminder\\n- Calendar\\n- BusyCal\\n- Things\\n- 2To\\n- Wunderlist \\n- Todoist\\n\\nAirmail 4 include Airmail Pro Subscription.\\n\\nAirmail Pro Features:\\n- Access to iPhone and iPad\\n- New Design\\n- Smart box\\n- New Rendering\\n- New Search\\n- New Themes\\n- Custom Actions\\n- Customizable Layout\\n- Live Support\\n\\nNotes:\\n• Airmail Pro is free for all users that are subscribed to Airmail Pro for iOS or have purchased Airmail 3 since 1st January 2019.\\n• Previous users can still use Airmail with all the features they have purchased for under Preferences>General> Airmail Legacy.\\n• New Users can try Airmail without Multi Account, and limited capabilities.\\n\\n$2.99 Monthly, $9.99 Yearly\\n\\n---\\n\\n• Price may vary by location and promotion.\\n• Subscriptions will be charged to your credit card through your iTunes account. \\n• Your subscription will automatically renew unless canceled at least 24 hours before the end of the current period.\\n• Manage your subscriptions in Account Settings after purchase. \\n• Any unused portion of a free trial peri​od, will be forfeited when the user purchases a subscription.\\n• Account will be charged for renewal within 24-hours prior to the end of the current period, and identify the cost of the renewal\\n\\n\\nPrivacy Policy: https://airmailapp.com/privacymac.html\\nTerms of Service: https://airmailapp.com/eulamac.html\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Productivity\",\n\t\t\t\t\"Utilities\"\n\t\t\t],\n\t\t\t\"artistId\": 389546852,\n\t\t\t\"artistName\": \"Bloop S.R.L.\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"it.bloop.airmail2\",\n\t\t\t\"version\": \"4.1.6\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple118/v4/4f/fe/c7/4ffec732-9c5c-e861-4ebe-284d67391792/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple128/v4/3e/aa/5f/3eaa5f22-7306-9848-0aef-9c53013f9bd7/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple128/v4/f6/af/28/f6af2812-b83e-6c0e-c89c-197381ee1c3b/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple118/v4/59/e4/dc/59e4dc92-bede-17f4-2933-365f3d60244e/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple128/v4/de/ad/28/dead28bc-2e1f-b3f3-73a8-e970c1bfce6b/pr_source.jpg/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/a0/68/f8/a068f85a-f72a-1efb-d0ee-0543fb97d48b/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/a0/68/f8/a068f85a-f72a-1efb-d0ee-0543fb97d48b/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/a0/68/f8/a068f85a-f72a-1efb-d0ee-0543fb97d48b/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/rocket-chat-technologies-corp/id1148477217?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1086818840,\n\t\t\t\"trackName\": \"Rocket.Chat\",\n\t\t\t\"releaseDate\": \"2016-03-09T18:02:58Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6007\",\n\t\t\t\t\"6002\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.10.0\",\n\t\t\t\"primaryGenreName\": \"Productivity\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-03-13T00:15:30Z\",\n\t\t\t\"releaseNotes\": \"Improvements:\\n- Update to Electron 7\\n- Performance tweaks\\n- Better handling of power events\\n\\nBug fixes:\\n- Custom spell checking dictionaries\\n- Screen sharing in Jitsi\\n- TouchBar buttons\\n- Embed dialogs\\n- Notification avatars\",\n\t\t\t\"primaryGenreId\": 6007,\n\t\t\t\"sellerName\": \"Rocket.Chat Technologies Corp.\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Rocket.Chat\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"AM\",\n\t\t\t\t\"AR\",\n\t\t\t\t\"BN\",\n\t\t\t\t\"BG\",\n\t\t\t\t\"CA\",\n\t\t\t\t\"HR\",\n\t\t\t\t\"CS\",\n\t\t\t\t\"DA\",\n\t\t\t\t\"NL\",\n\t\t\t\t\"EN\",\n\t\t\t\t\"ET\",\n\t\t\t\t\"FI\",\n\t\t\t\t\"FR\",\n\t\t\t\t\"DE\",\n\t\t\t\t\"EL\",\n\t\t\t\t\"GU\",\n\t\t\t\t\"HE\",\n\t\t\t\t\"HI\",\n\t\t\t\t\"HU\",\n\t\t\t\t\"ID\",\n\t\t\t\t\"IT\",\n\t\t\t\t\"JA\",\n\t\t\t\t\"KN\",\n\t\t\t\t\"KO\",\n\t\t\t\t\"LV\",\n\t\t\t\t\"LT\",\n\t\t\t\t\"MS\",\n\t\t\t\t\"ML\",\n\t\t\t\t\"MR\",\n\t\t\t\t\"NB\",\n\t\t\t\t\"FA\",\n\t\t\t\t\"PL\",\n\t\t\t\t\"PT\",\n\t\t\t\t\"RO\",\n\t\t\t\t\"RU\",\n\t\t\t\t\"SR\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"SK\",\n\t\t\t\t\"SL\",\n\t\t\t\t\"ES\",\n\t\t\t\t\"SW\",\n\t\t\t\t\"SV\",\n\t\t\t\t\"TA\",\n\t\t\t\t\"TE\",\n\t\t\t\t\"TH\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"TR\",\n\t\t\t\t\"UK\",\n\t\t\t\t\"VI\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"69450749\",\n\t\t\t\"sellerUrl\": \"https://rocket.chat/\",\n\t\t\t\"contentAdvisoryRating\": \"17+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/rocket-chat/id1086818840?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"17+\",\n\t\t\t\"description\": \"Rocket.Chat is a Web Chat Server, developed in JavaScript, using the Meteor full-stack framework. It is a great solution for communities and companies wanting to privately host their own chat service or for developers looking forward to building and evolve their own chat platforms. With Rocket.Chat, you can send a group message, send 1:1 message, share files, integrate with your favorite products, and more!\\n\\nKEY FEATURES:\\n\\n* Free Open Source Software\\n* Hassle free MIT license\\n* BYOS (bring your own server)\\n* Multiple Rooms\\n* Direct Messages\\n* Private Groups\\n* Public Channels\\n* Desktop and Mobile Notifications\\n* Edit and Delete Sent Messages\\n* Mentions\\n* Avatars\\n* Markdown\\n* Emojis\\n* Transcripts / History\\n* File Upload / Sharing\\n* I18n - [Internationalization with Lingohub]\\n* Hubot Friendly - [Hubot Integration Project]\\n* Media Embeds\\n* Link Previews\\n* LDAP Authentication\\n* REST-full APIs\\n* Remote Locations Video Monitoring\\n* Native Cross-Platform Desktop Application\\n\\nNEWS:\\n\\nFeatured on: Hacker News, Product Hunt, JavaScript Weekly, WWWhatsNew, ClasesDePeriodismo\\n\\nGET IT NOW:\\n\\n* Check out at https://rocket.chat\\n* ONE-CLICK-DEPLOYMENT – See instruction on our GitHub repository\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Productivity\",\n\t\t\t\t\"Utilities\"\n\t\t\t],\n\t\t\t\"artistId\": 1148477217,\n\t\t\t\"artistName\": \"Rocket.Chat Technologies Corp.\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"chat.rocket\",\n\t\t\t\"version\": \"2.17.9\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple124/v4/8b/59/37/8b593789-a69e-9a22-9477-049f7466917e/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple124/v4/4b/3a/f6/4b3af6d0-3448-2ee6-f649-fe6221e708bf/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple114/v4/91/27/54/91275485-91b8-292e-f82b-829b14e9226d/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple114/v4/e6/de/3f/e6de3ffa-624e-588f-1e1c-623df367f53b/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple124/v4/2a/93/0b/2a930bef-cbd3-1f03-35e4-6389d5f9d7c5/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple124/v4/26/78/d9/2678d9e3-4b91-8d9c-7b59-5ebd51847d3d/pr_source.jpg/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple114/v4/ea/82/b9/ea82b92a-9e6e-6e59-b27b-e204d956fef3/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple114/v4/ea/82/b9/ea82b92a-9e6e-6e59-b27b-e204d956fef3/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple114/v4/ea/82/b9/ea82b92a-9e6e-6e59-b27b-e204d956fef3/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/tencent-technology-shenzhen-company-limited/id292374531?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1189898970,\n\t\t\t\"trackName\": \"WeCom-Business IM & Work Tools\",\n\t\t\t\"releaseDate\": \"2018-02-27T07:21:11Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6000\",\n\t\t\t\t\"6002\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.11\",\n\t\t\t\"primaryGenreName\": \"Business\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-09-01T02:01:05Z\",\n\t\t\t\"releaseNotes\": \"I.Improved Multiple Productivity Tools\\n1.WeDoc \\n-Optimized question editing and added three new questions: Picture, File, Location and Date. You can support timed repeated collection.\\n-A variety of templates are newly added to the template center based on different industries, and custom templates are supported. Users can save any template to the template center.\\n-Added comment panel, where you can quickly browse all comments of documents.\\n2.WeDrive\\n-Added \\\"Preview only\\\" permission and watermark settings. You can preview files in mainstream formats. It is supported in WeDrive Pro.\\n3.Optimized Event APIs. Companies can obtain events on the calendar created through APIs, allowing data sharing from the existing system.\\n4.Live\\n-Admins can customize the permission to initiate live video for externals. Only allowed members can initiate live videos for external customers and partners.\\n\\nII.Optimized Basic OA Apps\\n1.Approvals\\n-You can set the permissions for approvers to view or edit the approval application fields. In this way, you can hide content from the specified approvers or allow them to modify the application content.\\n-When setting the approval process, you can copy the process from other templates.\\n-The duration of leave, offsite, business trip, and overtime work can be modified and counted on a daily basis. When the duration is set to \\\"Working Days\\\", the overtime and leave duration can be calculated more accurately according to the punch rules for the applicant.\",\n\t\t\t\"primaryGenreId\": 6000,\n\t\t\t\"sellerName\": \"Tencent Technology (Shenzhen) Company Limited\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"WeCom-Business IM & Work Tools\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"ZH\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"87361336\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/wecom-business-im-work-tools/id1189898970?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"WeCom is a business communication and office collaboration tool developed by Tencent WeChat Team. WeCom provides the familiar communication experience as WeChat and connects with WeChat in an all-round manner. It also offers productivity tools such as Event, Meeting, WeDoc and WeDrive, and flexible OA apps for effective business communication and management. \\nWeCom has been widely adopted by millions of leading organizations, including Rainbow, P&G, Cartier, WalMart, Chow Tai Fook, L'Oreal, IKEA, Bank of China, PICC, Deppon Express, and Changan Automobile.\\n\\n1. A familiar communication experience\\n[Ease of Use] Provides a IM experience consistent with WeChat’s.\\n[Reliable Storage] Enables real-time message syncing to PCs, mobiles phones, the cloud, and other devices.\\n[Efficient Communication] Allows users to check message read status to ensure effective communication.\\n[Corporate Directory] Allows administrators to batch import and manage corporate directory. Finding co-workers has never been easier.\\n\\n2. Connecting with WeChat\\n[Exchange Messages] Add WeChat users as contacts and offer services via private or group chats.\\n[Contact Customers] Companies can view and manage customers added by members, and assign customers of former members.\\n\\n3. Integrated with kinds of efficiency tool\\n[Event Management] Simultaneously, through \\\"Make an Appointment\\\", you can easily check the idle/busy status of the group members and select the appropriate time to start the event. Members will receive the event invitation in their Event app.\\n[Multi-person Meeting] Initiate and join online meetings anytime & anywhere, allowing sharing documents and screens among up to 25 participants, and providing some management features for hosts.\\n[WeDoc] Online real-time collaborative docs and sheets. Edits can be updated in real-time, freeing collaborators from transferring the files with each other.\\n[WeDrive] Create a shared space with colleagues to keep track of the latest version. Edits can be updated in real-time.Companies can manage all company files in one place and allow audit by members, ensuring company data security.\\n[Business Mailbox] Send and receive business emails and forward to Group Chats if needed.\\n\\n4. Diversified Office Apps\\n[Basic Office Apps] Preset ready-to-use office apps such as Attendance, Approvals, Reports, Announcement, and Forum.\\n[Third-party Apps] Provide companies with high-quality third-party apps and hardware, covering mobile office, and other fields, as well as smart attendance, unlimited screen casting, and meeting television.\\n[APIs] Provide various APIs, making it easier for you to integrate company apps.\\n\\n5. Strong security capabilities\\n[all-round safeguard] Based on the integration of offense and defense capabilities of Tencent over the past 20 years, WeCom is the first domestic office product to pass SOC2Type2 auditing, and has obtained ISO27018, ISO20000, ISO27001, and national three-level certifications to provide reliable data security guarantee for companies.\\n\\nWeCom, Offering Every Enterprise their own WeChat\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Business\",\n\t\t\t\t\"Utilities\"\n\t\t\t],\n\t\t\t\"artistId\": 292374531,\n\t\t\t\"artistName\": \"Tencent Technology (Shenzhen) Company Limited\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.tencent.WeWorkMac\",\n\t\t\t\"version\": \"3.0.30\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"supportedDevices\": [\n\t\t\t\t\"iPadMini4Cellular-iPadMini4Cellular\",\n\t\t\t\t\"iPadPro-iPadPro\",\n\t\t\t\t\"iPhone11ProMax-iPhone11ProMax\",\n\t\t\t\t\"iPadSeventhGenCellular-iPadSeventhGenCellular\",\n\t\t\t\t\"iPhone5s-iPhone5s\",\n\t\t\t\t\"iPadSeventhGen-iPadSeventhGen\",\n\t\t\t\t\"MacDesktop-MacDesktop\",\n\t\t\t\t\"iPad611-iPad611\",\n\t\t\t\t\"iPadAir2Cellular-iPadAir2Cellular\",\n\t\t\t\t\"iPadMini4-iPadMini4\",\n\t\t\t\t\"iPadPro97-iPadPro97\",\n\t\t\t\t\"iPad74-iPad74\",\n\t\t\t\t\"iPadProFourthGenCellular-iPadProFourthGenCellular\",\n\t\t\t\t\"iPadAir-iPadAir\",\n\t\t\t\t\"iPad878-iPad878\",\n\t\t\t\t\"iPadAirCellular-iPadAirCellular\",\n\t\t\t\t\"iPodTouchSeventhGen-iPodTouchSeventhGen\",\n\t\t\t\t\"iPhone11Pro-iPhone11Pro\",\n\t\t\t\t\"iPadMini5-iPadMini5\",\n\t\t\t\t\"iPadMini3Cellular-iPadMini3Cellular\",\n\t\t\t\t\"iPhone6-iPhone6\",\n\t\t\t\t\"iPadMini3-iPadMini3\",\n\t\t\t\t\"iPad71-iPad71\",\n\t\t\t\t\"iPadProSecondGen-iPadProSecondGen\",\n\t\t\t\t\"iPadProSecondGenCellular-iPadProSecondGenCellular\",\n\t\t\t\t\"iPadAir2-iPadAir2\",\n\t\t\t\t\"iPhoneXR-iPhoneXR\",\n\t\t\t\t\"iPhoneSE-iPhoneSE\",\n\t\t\t\t\"iPadPro97Cellular-iPadPro97Cellular\",\n\t\t\t\t\"iPad856-iPad856\",\n\t\t\t\t\"iPadAir3-iPadAir3\",\n\t\t\t\t\"iPad834-iPad834\",\n\t\t\t\t\"iPad76-iPad76\",\n\t\t\t\t\"iPhone8Plus-iPhone8Plus\",\n\t\t\t\t\"iPadMiniRetinaCellular-iPadMiniRetinaCellular\",\n\t\t\t\t\"iPhone11-iPhone11\",\n\t\t\t\t\"iPadMiniRetina-iPadMiniRetina\",\n\t\t\t\t\"iPad75-iPad75\",\n\t\t\t\t\"iPadProCellular-iPadProCellular\",\n\t\t\t\t\"iPhone8-iPhone8\",\n\t\t\t\t\"iPhoneX-iPhoneX\",\n\t\t\t\t\"iPad812-iPad812\",\n\t\t\t\t\"iPhone7-iPhone7\",\n\t\t\t\t\"iPhone6sPlus-iPhone6sPlus\",\n\t\t\t\t\"iPhoneSESecondGen-iPhoneSESecondGen\",\n\t\t\t\t\"iPadAir3Cellular-iPadAir3Cellular\",\n\t\t\t\t\"iPhone6s-iPhone6s\",\n\t\t\t\t\"iPhone6Plus-iPhone6Plus\",\n\t\t\t\t\"iPad72-iPad72\",\n\t\t\t\t\"iPhoneXS-iPhoneXS\",\n\t\t\t\t\"iPhoneXSMax-iPhoneXSMax\",\n\t\t\t\t\"iPodTouchSixthGen-iPodTouchSixthGen\",\n\t\t\t\t\"iPad73-iPad73\",\n\t\t\t\t\"iPadMini5Cellular-iPadMini5Cellular\",\n\t\t\t\t\"iPad612-iPad612\",\n\t\t\t\t\"iPhone7Plus-iPhone7Plus\",\n\t\t\t\t\"iPadProFourthGen-iPadProFourthGen\"\n\t\t\t],\n\t\t\t\"advisories\": [],\n\t\t\t\"isGameCenterEnabled\": false,\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple114/v4/f5/c7/3d/f5c73d36-4ce5-5d17-41c9-ea7fe465ca71/f3972f46-f6e9-4c09-a114-4d3c3c2c34b0_Main_iPhone_Plus.png/392x696bb.png\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple114/v4/d4/24/0d/d4240dda-e267-ce51-5e4f-7714a2ca5a7a/fabfeffa-a3c0-4651-9823-fc81519ec21c_Discord_iPhone_Plus.png/392x696bb.png\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple114/v4/9d/da/6f/9dda6f0a-2d3f-3b24-ccf3-ea0186a51324/0ff3934b-cd50-4b5c-8ab2-5a5385521508_Slack_iPhone_Plus.png/392x696bb.png\"\n\t\t\t],\n\t\t\t\"ipadScreenshotUrls\": [\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple124/v4/cb/c6/7f/cbc67f3d-f4fd-44e2-e2ed-053dee565346/ffab9b81-c9c1-4eaf-8cb0-a6ae649725de_Main_-_iPads.png/576x768bb.png\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple114/v4/72/d1/be/72d1be98-b513-1bde-9660-3506068d99f0/52fee114-79d9-470d-999b-d677ac0cdac5_Discord_iPads.png/576x768bb.png\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple124/v4/92/77/66/927766d7-d61a-0133-49ee-f38153335b99/4838fdf7-45a1-4ea1-a1be-cf4ce9e20172_Slack_iPads.png/576x768bb.png\"\n\t\t\t],\n\t\t\t\"appletvScreenshotUrls\": [],\n\t\t\t\"artworkUrl60\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple114/v4/89/f3/1e/89f31e56-bedd-4f2c-d86b-f3bb775fd7d4/source/60x60bb.jpg\",\n\t\t\t\"artworkUrl512\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple114/v4/89/f3/1e/89f31e56-bedd-4f2c-d86b-f3bb775fd7d4/source/512x512bb.jpg\",\n\t\t\t\"artworkUrl100\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple114/v4/89/f3/1e/89f31e56-bedd-4f2c-d86b-f3bb775fd7d4/source/100x100bb.jpg\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/peroxaan-studios-llc/id1492913322?uo=4\",\n\t\t\t\"features\": [\n\t\t\t\t\"iosUniversal\"\n\t\t\t],\n\t\t\t\"kind\": \"software\",\n\t\t\t\"trackId\": 1492913323,\n\t\t\t\"trackName\": \"Talon – Webhooks & More\",\n\t\t\t\"releaseDate\": \"2020-06-28T07:00:00Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6026\",\n\t\t\t\t\"6002\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"13.0\",\n\t\t\t\"primaryGenreName\": \"Developer Tools\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-08-24T14:19:01Z\",\n\t\t\t\"releaseNotes\": \"Introducing Talon Pro. Talon Pro is an expansion on the current features of Talon. Talon Pro allows you to shorten links, and more! It's $1.99 USD - but more features will be coming to Talon Pro in later updates.\\n\\nAlso, we've added custom webhooks to the app! You can now run whatever POST Request you'd like.\",\n\t\t\t\"primaryGenreId\": 6026,\n\t\t\t\"sellerName\": \"Peroxaan Studios, LLC\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Talon – Webhooks & More\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"27502592\",\n\t\t\t\"sellerUrl\": \"https://peroxaan.com/Talon\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 4.77777999999999991587174008600413799285888671875,\n\t\t\t\"userRatingCountForCurrentVersion\": 9,\n\t\t\t\"averageUserRating\": 4.77777999999999991587174008600413799285888671875,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/talon-webhooks-more/id1492913323?uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Talon is a simple tool for users to use, manage, and work with Webhooks on Discord and Slack. It's very easy to use, and allows a larger audience to work with Webhooks in a simple way, without requiring you to know how to code. Talon gets rid of everything complex, and gives you a nice and easy to use Interface thats familiar to use. We built Talon to take advantage of the features that Discord and Slack offer. Talon allows you to save and copy your links inside of the app, so you don't have to constantly go back and forth just to use the App. Also with Talon, you can run POST Requests to any service, just in case Talon does not yet offer something you have in mind.\\n\\nFor even more features, you can purchase Talon Pro. Talon Pro is a one time purchase that allows you to shorten links with Talon - and gives you more customizability. Talon Pro will be growing more with future updates.\\n\\nWant to suggest something for a future Talon update? Contact us!\\n\\nNow, that sounds pretty cool and all - but this is just the beginning. Stay tuned for future updates that'll bring more features and functionality to Talon!\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Developer Tools\",\n\t\t\t\t\"Utilities\"\n\t\t\t],\n\t\t\t\"artistId\": 1492913322,\n\t\t\t\"artistName\": \"Peroxaan Studios, LLC\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.peroxaan.Talon\",\n\t\t\t\"version\": \"1.2\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 9\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple118/v4/48/6d/7f/486d7fa8-fc1c-b537-9983-7c842da60afb/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple118/v4/db/40/87/db40870b-a6b5-8952-ab98-acfa27f92166/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple118/v4/5a/7d/1f/5a7d1f19-4bc4-7309-ae08-a4cce36fef8c/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple118/v4/ac/b5/27/acb5278b-dcdb-e52b-62f8-c300013fabc3/pr_source.jpg/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple114/v4/b2/98/67/b29867d9-2e76-8ca6-6a12-a1ea8bed2be5/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple114/v4/b2/98/67/b29867d9-2e76-8ca6-6a12-a1ea8bed2be5/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple114/v4/b2/98/67/b29867d9-2e76-8ca6-6a12-a1ea8bed2be5/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/shanghai-best-oray-information-technology-co-ltd/id551941462?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1305707014,\n\t\t\t\"trackName\": \"Pgy\",\n\t\t\t\"releaseDate\": \"2018-01-10T06:10:10Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6002\",\n\t\t\t\t\"6000\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.12\",\n\t\t\t\"primaryGenreName\": \"Utilities\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-08-31T02:19:25Z\",\n\t\t\t\"releaseNotes\": \"Update : \\n\\n1. Optimize the interface and icons. \\n\\n2. Repair known bug\",\n\t\t\t\"primaryGenreId\": 6002,\n\t\t\t\"sellerName\": \"Shanghai best oray information s&t co.,ltd\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Pgy\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\",\n\t\t\t\t\"ZH\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"2352150\",\n\t\t\t\"sellerUrl\": \"https://pgy.oray.com\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/pgy/id1305707014?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Pgy is a fast to build off-site virtual local area network APP software. Using a new independent research and development of Internet technology, through the network, to bring users a convenient network experience. Through the dandelion can be achieved remote access to local area network under the file, online game and other functions; at the same time can help small and medium enterprises quickly open up the branch or store between the remote network, mobile office, file sharing, remote monitoring, private LAN structures and other functions.\\n\\nThe main function:\\n1. Off-site file sharing: easy to achieve more documents, important data, files and other resource sharing, support anytime, anywhere browsing\\n2. Remote real-time view video monitoring: support real-time understanding of the operation of the branch, at any time to remotely view the details of the operation of the branch, video surveillance\\n3. Remote mobile office: connect work and life, easy access to the company's OA system, file server, etc., at home to visit the office computer\\n\\nInstructions:\\nAn APP only one step will be able to achieve intelligent networking features:\\n== different equipment [such as two mobile phones] at the same time download, install dandelion APP, landing the same oray account, that is, to complete the automatic network.\\n\\nDandelion, step by step to build a virtual local area network, from the horizon if the neighbors.\\nMore games, please pay attention: www.oray.comDandelion is a APP that can quickly build virtual lans. Using the new self-developed network technology, it can penetrate the Intranet and bring convenient network experience to users. Through dandelion can realize remote access LAN files, online game play and other functions; At the same time, it can help small and medium-sized enterprises to quickly open the long-distance network between branches or stores, realizing mobile office, file sharing, remote monitoring, private LAN building and other functions. \\n\\nMain functions: \\n1. To realize file sharing in different places: to easily realize multiple documents, important data, files and other resources to share, and to support browsing each other anytime and anywhere \\n2. Remote real-time view of video monitoring: support real-time understanding of the operation of each branch, remotely check the operation details of each branch, video monitoring, etc \\n3. Remote mobile office: connect work and life, easy access to the company's OA system, file server, etc., can access the office computer at home \\n4. Build personal private LAN: good gay friends love to beat boss, set up personal private LAN, realize multiplayer online games, enjoy the fun of games, gay love not cool \\n\\nUsage: \\nOne APP only takes one step to realize intelligent networking: \\nDifferent devices, such as two phones, download and install dandelion APP, and log on to the same oray account, which is to complete the automatic networking. \\n\\nDandelion, build a virtual LAN step by step, the end of the world. \\nFor more, please follow: www.oray.com\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Utilities\",\n\t\t\t\t\"Business\"\n\t\t\t],\n\t\t\t\"artistId\": 551941462,\n\t\t\t\"artistName\": \"Shanghai Best Oray Information Technology Co., Ltd.\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.oray.pgy.PgyVisitorMac\",\n\t\t\t\"version\": \"3.4.32010\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple118/v4/f8/42/8d/f8428dc7-22fd-a938-97f9-f1538ce4042a/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple118/v4/4a/d6/08/4ad60824-ae70-8fcb-261b-be798534e8ab/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple118/v4/4a/d6/08/4ad60824-ae70-8fcb-261b-be798534e8ab/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple118/v4/4a/d6/08/4ad60824-ae70-8fcb-261b-be798534e8ab/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/islandbit/id1073040697?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1271281910,\n\t\t\t\"trackName\": \"Activebot for Slack\",\n\t\t\t\"releaseDate\": \"2017-09-30T10:35:35Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6000\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.9\",\n\t\t\t\"primaryGenreName\": \"Business\",\n\t\t\t\"currentVersionReleaseDate\": \"2017-09-30T10:35:35Z\",\n\t\t\t\"primaryGenreId\": 6000,\n\t\t\t\"sellerName\": \"Islandbit Inc.\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Activebot for Slack\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"4274788\",\n\t\t\t\"sellerUrl\": \"https://www.islandbit.com/activebot-for-slack/\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/activebot-for-slack/id1271281910?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Activebot for Slack prevents Slack from going idle due to inactivity.\\n\\nNOTES:\\nThis application requires Slack authentication using one of the following methods:\\n1) \\\"Activebot for Slack\\\" app installed for your team\\n2) Legacy token\\n\\nPlease verify you have access to adding apps to your Slack team or generating legacy tokens before purchasing this application at:\\n\\nhttps://api.slack.com/custom-integrations/legacy-tokens\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Business\"\n\t\t\t],\n\t\t\t\"artistId\": 1073040697,\n\t\t\t\"artistName\": \"Islandbit\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.islandbit.Activebot\",\n\t\t\t\"version\": \"1.0\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple49/v4/dd/08/a4/dd08a4fe-9df6-3265-c2d3-2c0cf68203e0/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple49/v4/8d/ad/b6/8dadb62c-32d2-621c-001d-0f46c57ad7ae/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple49/v4/a3/94/68/a3946880-3cf4-047e-71be-32f3ce8ea42f/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple49/v4/a3/94/68/a3946880-3cf4-047e-71be-32f3ce8ea42f/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple49/v4/a3/94/68/a3946880-3cf4-047e-71be-32f3ce8ea42f/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/gui-ning/id1086339124?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1097510182,\n\t\t\t\"trackName\": \"Building Block - Castle & City Craft Simulator\",\n\t\t\t\"releaseDate\": \"2016-04-01T22:03:42Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6014\",\n\t\t\t\t\"7017\",\n\t\t\t\t\"7015\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"$2.99\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.7\",\n\t\t\t\"primaryGenreName\": \"Games\",\n\t\t\t\"currentVersionReleaseDate\": \"2016-04-12T00:18:16Z\",\n\t\t\t\"releaseNotes\": \"bugfixed\",\n\t\t\t\"primaryGenreId\": 6014,\n\t\t\t\"sellerName\": \"GUI NING\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Building Block - Castle & City Craft Simulator\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\",\n\t\t\t\t\"ZH\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"2165740\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/building-block-castle-city-craft-simulator/id1097510182?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"BuildingBlock is a sandbox game with pixel styles & first-person.\\n \\n   BuildingBlock has no specific goals for the player to accomplish, allowing players a large amount of freedom in choosing how to play the game. BuildingBlock enable players to build constructions out of textured cubes in a 3D procedurally generated world.\\n \\n   Players have unlimited resources to build with and the ability to fly. At the start of the game, the player is placed on the surface of a procedurally generated and virtually infinite game world. The world is divided into biomes ranging from deserts to jungles to snowfields.Players can walk across the terrain consisting of plains, mountains, forests, caves, and various water bodies.\\n\\n   The core gameplay revolves around breaking and placing blocks. The game world is composed of rough 3D objects—mainly cubes—arranged in a fixed grid pattern and representing different materials, such as dirt, stone, various ores, water, lava, tree trunks, etc. While players can move freely across the world, objects can only be placed at fixed locations on the grid. Players can gather these material blocks and place them elsewhere, thus allowing for various constructions.\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Games\",\n\t\t\t\t\"Strategy\",\n\t\t\t\t\"Simulation\"\n\t\t\t],\n\t\t\t\"artistId\": 1086339124,\n\t\t\t\"artistName\": \"GUI NING\",\n\t\t\t\"price\": 2.99,\n\t\t\t\"bundleId\": \"com.gnmac.buildingblock\",\n\t\t\t\"version\": \"3.6\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple71/v4/6c/28/03/6c280331-3486-49e6-9668-5b15cc05ebcd/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple62/v4/d8/1c/3c/d81c3c7e-9bb0-8e86-f9f1-0395986e66f0/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple71/v4/a5/e1/30/a5e130a9-58e8-b993-63ab-ba43ed816a85/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple71/v4/cc/93/c9/cc93c904-3d54-c25d-5ec4-81900dcb3511/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple62/v4/4c/1e/a0/4c1ea0de-411a-2602-0ea1-040ea79ae172/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple114/v4/00/1d/03/001d037b-392e-e2d6-126b-21e02f8dc263/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple114/v4/00/1d/03/001d037b-392e-e2d6-126b-21e02f8dc263/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple114/v4/00/1d/03/001d037b-392e-e2d6-126b-21e02f8dc263/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/shape-gmbh/id285688937?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1137958278,\n\t\t\t\"trackName\": \"IM+ All-in-One Messenger\",\n\t\t\t\"releaseDate\": \"2016-08-03T13:01:02Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6005\",\n\t\t\t\t\"6012\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"$17.99\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.10.0\",\n\t\t\t\"primaryGenreName\": \"Social Networking\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-08-11T16:00:02Z\",\n\t\t\t\"releaseNotes\": \"- Various UI and counter fixes\\n\\nEnjoy and let us know your feedback,\\nYour IM+ Team :)\",\n\t\t\t\"primaryGenreId\": 6005,\n\t\t\t\"sellerName\": \"SHAPE GmbH\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"IM+ All-in-One Messenger\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"AM\",\n\t\t\t\t\"AR\",\n\t\t\t\t\"BN\",\n\t\t\t\t\"BG\",\n\t\t\t\t\"CA\",\n\t\t\t\t\"HR\",\n\t\t\t\t\"CS\",\n\t\t\t\t\"DA\",\n\t\t\t\t\"NL\",\n\t\t\t\t\"EN\",\n\t\t\t\t\"ET\",\n\t\t\t\t\"FI\",\n\t\t\t\t\"FR\",\n\t\t\t\t\"DE\",\n\t\t\t\t\"EL\",\n\t\t\t\t\"GU\",\n\t\t\t\t\"HE\",\n\t\t\t\t\"HI\",\n\t\t\t\t\"HU\",\n\t\t\t\t\"ID\",\n\t\t\t\t\"IT\",\n\t\t\t\t\"JA\",\n\t\t\t\t\"KN\",\n\t\t\t\t\"KO\",\n\t\t\t\t\"LV\",\n\t\t\t\t\"LT\",\n\t\t\t\t\"MS\",\n\t\t\t\t\"ML\",\n\t\t\t\t\"MR\",\n\t\t\t\t\"NB\",\n\t\t\t\t\"FA\",\n\t\t\t\t\"PL\",\n\t\t\t\t\"PT\",\n\t\t\t\t\"RO\",\n\t\t\t\t\"RU\",\n\t\t\t\t\"SR\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"SK\",\n\t\t\t\t\"SL\",\n\t\t\t\t\"ES\",\n\t\t\t\t\"SW\",\n\t\t\t\t\"SV\",\n\t\t\t\t\"TA\",\n\t\t\t\t\"TE\",\n\t\t\t\t\"TH\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"TR\",\n\t\t\t\t\"UK\",\n\t\t\t\t\"VI\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"67130312\",\n\t\t\t\"sellerUrl\": \"https://plus.im\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/im-all-in-one-messenger/id1137958278?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"IM+ supports Zoom, WhatsApp, Telegram, Facebook Messenger, Facebook, Twitter, Slack, Skype, Gmail, Outlook, Hangouts, LinkedIn Messaging, Instagram, SnapMap, WeChat, ChatWork, HipChat, and Facebook Pages in one simple app.\\n\\nLog in once into your favorite messengers and video communicators, and gone will be the days of endless app switching.\\n\\nSome of the best features:\\nVideo and voice calls on Zoom and Skype from one app\\nNavigate through your accounts using the sidebar or hotkeys \\nAdd multiple accounts per service, e.g. add a couple Twitter profiles\\nDistinguish messengers easier with color tags and filter them by profile tags\\nSupport for file sharing\\nManage notification settings for all accounts at once or per service \\nGreat for remote workers\\n\\nThe whole IM+ experience was designed for Mac OS X. \\nIf IM+ improves your messaging life, we would appreciate an App Store review. Thank you!\\n\\nIM+ for iPhone has been used by over 10 million people and featured on Wired, Engadget, TechCrunch, Forbes, Bloomberg, The New York Times, and many more. And you will love IM+ on Mac too!\\n\\nLearn more about IM+ at www.shape.ag\\nWe listen to you, so send us your feedback, questions and feature requests on Twitter @implus or Facebook www.facebook.com/plusim\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Social Networking\",\n\t\t\t\t\"Lifestyle\"\n\t\t\t],\n\t\t\t\"artistId\": 285688937,\n\t\t\t\"artistName\": \"SHAPE GmbH\",\n\t\t\t\"price\": 17.99,\n\t\t\t\"bundleId\": \"com.shapeservices.implusosx\",\n\t\t\t\"version\": \"1.13\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple111/v4/00/30/f5/0030f509-ed0f-d322-f24a-133922506d10/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple91/v4/bb/d2/2d/bbd22d87-6f95-b0be-beb6-fb4c0b5e1afc/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple111/v4/f3/42/a7/f342a728-11c0-e736-473a-a183dc3c097b/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple111/v4/09/39/c1/0939c16d-c9e4-6342-16cb-607481f8264f/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple122/v4/35/6f/30/356f3094-6062-7fc9-c237-ab59035fc366/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/ec/6b/6d/ec6b6d54-e990-3468-da0f-e5516c37620b/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/ec/6b/6d/ec6b6d54-e990-3468-da0f-e5516c37620b/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/ec/6b/6d/ec6b6d54-e990-3468-da0f-e5516c37620b/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/d2-nova-corp/id1120545372?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1120731995,\n\t\t\t\"trackName\": \"Team.biz - Business Messaging\",\n\t\t\t\"releaseDate\": \"2016-09-03T10:32:21Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6000\",\n\t\t\t\t\"6007\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.10.0\",\n\t\t\t\"primaryGenreName\": \"Business\",\n\t\t\t\"currentVersionReleaseDate\": \"2019-11-14T00:51:05Z\",\n\t\t\t\"releaseNotes\": \"Function and UI enhancement. Security improvement. Support macOS10.15 Catalina.\\nWe are continuing to make updates to Team.Biz in response to your feature requests.\",\n\t\t\t\"primaryGenreId\": 6000,\n\t\t\t\"sellerName\": \"D2 Nova Corp\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Team.biz - Business Messaging\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"AM\",\n\t\t\t\t\"AR\",\n\t\t\t\t\"BN\",\n\t\t\t\t\"BG\",\n\t\t\t\t\"CA\",\n\t\t\t\t\"HR\",\n\t\t\t\t\"CS\",\n\t\t\t\t\"DA\",\n\t\t\t\t\"NL\",\n\t\t\t\t\"EN\",\n\t\t\t\t\"ET\",\n\t\t\t\t\"FI\",\n\t\t\t\t\"FR\",\n\t\t\t\t\"DE\",\n\t\t\t\t\"EL\",\n\t\t\t\t\"GU\",\n\t\t\t\t\"HE\",\n\t\t\t\t\"HI\",\n\t\t\t\t\"HU\",\n\t\t\t\t\"ID\",\n\t\t\t\t\"IT\",\n\t\t\t\t\"JA\",\n\t\t\t\t\"KN\",\n\t\t\t\t\"KO\",\n\t\t\t\t\"LV\",\n\t\t\t\t\"LT\",\n\t\t\t\t\"MS\",\n\t\t\t\t\"ML\",\n\t\t\t\t\"MR\",\n\t\t\t\t\"NB\",\n\t\t\t\t\"FA\",\n\t\t\t\t\"PL\",\n\t\t\t\t\"PT\",\n\t\t\t\t\"RO\",\n\t\t\t\t\"RU\",\n\t\t\t\t\"SR\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"SK\",\n\t\t\t\t\"SL\",\n\t\t\t\t\"ES\",\n\t\t\t\t\"SW\",\n\t\t\t\t\"SV\",\n\t\t\t\t\"TA\",\n\t\t\t\t\"TE\",\n\t\t\t\t\"TH\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"TR\",\n\t\t\t\t\"UK\",\n\t\t\t\t\"VI\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"86876996\",\n\t\t\t\"sellerUrl\": \"https://www.team.biz\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/team-biz-business-messaging/id1120731995?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"This is the messaging platform for professionals. We've brought the power and speed of a modern messaging app and added the capabilities needed for it to make sense within a work environment.\\n\\nUse Team.biz for free.  If you don't already have an account, you can sign up for one for free through the app.\\n\\n•  Create your own private team conversation space\\n•  Reach anyone on your team with direct messages\\n•  Have private conversations with a subset of your team\\n•  Create open topics that are viewable by everyone on your team\\n•  Safely communicate outside your team by inviting guests to a specific topic or conversation\\n•  Text out (SMS and MMS) to guests [This feature is limited to US phone numbers]\\n•  Hold a conversation with team members, guests, and text message participants (SMS and MMS) at the same time \\n•  Delegate admin responsibility to other users, so that they can manage your account\\n•  Maintain your message history\\n•  Share documents and images\\n•  Quickly see who's online, who's in the conversation, and who’s typing\\n•  Messages can be edited after they've been sent, so you can correct small errors and mistakes that would otherwise appear unprofessional\\n•  View the change history for any message, so you always will know what was originally said\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Business\",\n\t\t\t\t\"Productivity\"\n\t\t\t],\n\t\t\t\"artistId\": 1120545372,\n\t\t\t\"artistName\": \"D2 Nova Corp.\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.d2nova.teamasapmac\",\n\t\t\t\"version\": \"2.0.3\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/PurpleSource124/v4/33/f2/fd/33f2fdac-d025-d8e9-4945-5f97e9cc52d6/36ee117c-f4b0-4d22-b961-100f7f5b2ee2_1.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/PurpleSource124/v4/21/1b/ef/211bef90-4006-c47f-ecf4-fe7045a636ea/062ce278-6bc1-4d63-be85-52293e7ee4ac_2.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/PurpleSource124/v4/a2/75/b8/a275b835-d9aa-6c8a-f075-11f62788bcdf/89fca711-e8a5-4c1c-86e4-6dade08eead0_3.png/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/PurpleSource114/v4/14/01/3b/14013b1f-6047-7072-c8dc-cee3b743f379/633d921a-3778-45b6-b2cd-7fec1c190fb6_4.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/PurpleSource114/v4/fe/57/3f/fe573f18-6059-d6f0-c486-c448b82e20d4/78736982-88be-4cd2-a8f2-a73030a57d3a_5.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/PurpleSource124/v4/f9/c1/ae/f9c1ae33-6590-8686-847c-004d6f15bdfb/b2698bb2-c1f9-4059-bf53-d67111704c4d_6.png/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/PurpleSource124/v4/f3/06/c9/f306c9c4-9c32-e5c5-6ca2-2e625dde083e/e3be743f-2410-4e3e-af56-cf7b1b02bf40_7.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/PurpleSource114/v4/d6/e5/04/d6e50418-e1ea-3b13-c060-4c46f7c27462/cf8b7740-bdbb-40d4-b65b-6b5142f11b6a_8.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple124/v4/db/17/da/db17da9b-efbd-0e95-53ab-b506986dbec3/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple124/v4/db/17/da/db17da9b-efbd-0e95-53ab-b506986dbec3/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple124/v4/db/17/da/db17da9b-efbd-0e95-53ab-b506986dbec3/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/works-mobile-corp/id1012129121?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1029784963,\n\t\t\t\"trackName\": \"LINE WORKS\",\n\t\t\t\"releaseDate\": \"2016-07-07T08:07:12Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6000\",\n\t\t\t\t\"6007\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.12\",\n\t\t\t\"primaryGenreName\": \"Business\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-09-02T01:19:27Z\",\n\t\t\t\"releaseNotes\": \"- Fixed other bugs and improved other features\",\n\t\t\t\"primaryGenreId\": 6000,\n\t\t\t\"sellerName\": \"WORKS MOBILE Corp.\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"LINE WORKS\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\",\n\t\t\t\t\"JA\",\n\t\t\t\t\"KO\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"ZH\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"21001800\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/line-works/id1029784963?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"LINE WORKS texting/free calling services via PC version are available. \\nCommunicate with your colleagues more conveniently and quickly using the PC version.\\n\\n[Messaging function optimized for business]\\nYou can easily communicate with members in a team/group chat room synced with your company’s organization chart, and share works and files in Notes. You can also communicate for free with LINE users and as well as other LINE WORKS users.\\n※ Chatting with other company people is available after approval from the admin.\\n\\n[Transmission of multi files/photos and Neatly arranged screen]\\nYou can easily send many photos or files at once by using Drag & Drop. Were you distracted by many message windows scattered on the screen? It collects many message windows shown on the screen into one and arranges them neatly.\\n※ The maximum capacity and number of transmittable files : Maximum 100MB per each file, Maximum 20 files\\n※ If you set the feature through Settings > Message / Call > ‘Merge windows’, you can see the collected and arranged message windows from that moment.\\n\\n[Free voice and video call through PC!]\\nIsn’t it hard to explain by using messages? Now you can communicate more easily through free call service. By clicking the call icon from Colleague’s profile photo, you can use free voice and video call services. You can communicate with the Colleague while seeing each other’s faces despite the long distance between you and your Colleague.\\n\\n※ Available only for Mac OS X 10.12 and above.\\n※ In the case Lite products are used, some parts of the features are restricted.\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Business\",\n\t\t\t\t\"Productivity\"\n\t\t\t],\n\t\t\t\"artistId\": 1012129121,\n\t\t\t\"artistName\": \"WORKS MOBILE Corp.\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.naver.WorksOneApp\",\n\t\t\t\"version\": \"2.9.2\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple128/v4/21/00/ae/2100ae81-9e04-5936-f6fa-510ba86560ea/mzl.kcqgyxnk.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple118/v4/f7/34/e9/f734e9f6-09cb-b523-5f2c-1bde17972491/mzl.fpnstdmz.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple128/v4/8b/20/97/8b209744-90e0-de25-6b0a-816f0cf03a45/mzl.bhdbkhmo.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple128/v4/89/d7/36/89d736e4-e616-07fc-b676-243be06a2767/mzl.yoxlprei.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple128/v4/16/3e/6d/163e6d41-9e4d-02fa-62a2-d9bae16808cf/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple118/v4/07/f1/47/07f1477d-37a5-c3ff-abed-ed9e8e28a95a/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple118/v4/07/f1/47/07f1477d-37a5-c3ff-abed-ed9e8e28a95a/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple118/v4/07/f1/47/07f1477d-37a5-c3ff-abed-ed9e8e28a95a/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/appyogi-software/id1039633008?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1139742811,\n\t\t\t\"trackName\": \"One Chat All-in-One Messenger\",\n\t\t\t\"releaseDate\": \"2016-09-03T13:00:06Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6005\",\n\t\t\t\t\"6002\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"$19.99\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.11\",\n\t\t\t\"primaryGenreName\": \"Social Networking\",\n\t\t\t\"currentVersionReleaseDate\": \"2018-03-01T05:10:31Z\",\n\t\t\t\"releaseNotes\": \"▸ Implement touch ID Password unlock for macs with touch bar. \\n▸ Fixed Skype and WhatsApp freezing issue. \\n▸ Fixed Slack notification issue.  \\n▸ Fixed all the bugs reported on support tickets.\\n▸ Major bug fix.\\n▸ QQ & WeChat does not work for new accounts as they does not allow to use.\\n\\nImprovements in Previous versions:\\n\\n▸ Downloading the audio file in WhatsApp is fixed.\\n▸ New messaging service integrated -> Tinder chat\\n▸ WhatsApp video recording handled.\\n▸ HipChat automatic opening of Members List after new message arrival issue rectified.\\n▸ Slack login using single sign-on (SSO) is handled.\\n▸ Spelling check for all messaging services is enabled.\\n▸ Skype drag and drop image option fixed.\\n▸ Telegram image load issue with blue question mark handled\\n▸ Facebook two factor authentication login handled\\n▸ Added option to Enable/Disable sound notification alerts (in preferences)\\n▸ No Internet connection' pop-up showing even for weak signals rectified.\\n▸ Option to remember the password. \\n▸ New services added are IRC chat, MySMS, Tweetdeck. \\n▸ Option to stop GIF prompt while typing the message. \\n▸ Option to mark all messages as reading.\\n▸ Now you can send GIF instead of just a text message. \\n▸ Schedule message to send them later.\\n▸ FaceTime calling from WhatsApp\\n▸ FaceTime calling from Telegram\\n▸ Added Touch bar support for New MacBook Pro(2016)\\n▸ Improvements in User Interface\\n▸ Improved user preferences for more customisations\\n▸ Fixed Skype calling plugin.\\n▸▸ Multiple (Unlimited) Accounts for all messaging services.(hope you love it)\\n▸ Individual Notifications for every accounts added\\n▸ Rearrange messaging services on the menu.\\n▸ Fixed shortcuts keys. \\n▸ Added indicator for file download. \\n▸ Fixed network connection status. \\n▸ Take video and selfie from WhatsApp.\\n▸ Notification Badges for individual chats services. \\n▸ Added Twitter service\\n▸ Loading issue resolved\\n▸ Fixed Hangouts and Skype calling.\\n▸ Fixed upload of media, docs and other files from the folder. \\n▸ Added more services, Google Hangouts, HipChat, WeChat \\n▸ Supports New MacOS Sierra Version: 10.12\\n▸ Password Protection for privacy\\n▸ Now use two different accounts of every service(messenger)\\n▸ Add/Remove services from the left menu, as per the requirement.\\n▸ Customize Notifications as per different accounts.\\n▸ Fixed Media(Picture, Video or music) upload and download issue.\\n▸ Fixed URL click issue on Facebook messenger.\\n\\n▸ If you enjoy using \\\"One Chat\\\" App, Please review and rate. That keeps us motivated. \\n\\nNote: Some new and existing features might not work in below MacOS Sierra.\\nBut lower OS version users can use it with limited functionality. \\n\\nCurrent messaging services 22 and more coming:\\nWhatsApp, FB Messenger, Hangouts, Telegram, Skype, Slack, WeChat, HipChat, Twitter, Yahoo Chat, ICQ, Discord, GroupMe, QQ, Messenger for Facebook Pages, Fleep, VK, RocketChat, Tinder.\\n\\nUnder the hood improvements: \\n▸ Avg. CPU reduced from 10% to 3% \\n▸ Avg. Energy consumption reduced from High to Zero\\n\\nFeatures in next version: \\n▸ More messaging services. (Instagram, Line, Kik, Linkedin, wire, Tinder, Tumbler, XXMP, Steam, Grape)\\n▸ And many more surprises.\\n\\nSpecial Thanks to our all existing user with following users who are helping us with suggestions and support.\\nCosmin Miron\\nRon Brathwaite\\nDirk Gates\\nLuis Neves\\nRahulmhatre\\nwa.k\\nAlexander Leijenaar. \\n\\nWe respect all the suggestions and requests from our users and implement, which we feel are most important and solves the real problems of all users. \\n\\n\\nOverall, using One Chat does provide a couple of advantages when it comes to security.\\nIt does not store any messages or logins.\",\n\t\t\t\"primaryGenreId\": 6005,\n\t\t\t\"sellerName\": \"AppYogi Software\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"One Chat All-in-One Messenger\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"DA\",\n\t\t\t\t\"NL\",\n\t\t\t\t\"EN\",\n\t\t\t\t\"FI\",\n\t\t\t\t\"FR\",\n\t\t\t\t\"DE\",\n\t\t\t\t\"EL\",\n\t\t\t\t\"ID\",\n\t\t\t\t\"IT\",\n\t\t\t\t\"JA\",\n\t\t\t\t\"KO\",\n\t\t\t\t\"MS\",\n\t\t\t\t\"NB\",\n\t\t\t\t\"PT\",\n\t\t\t\t\"RU\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"ES\",\n\t\t\t\t\"SV\",\n\t\t\t\t\"TH\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"TR\",\n\t\t\t\t\"VI\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"8149607\",\n\t\t\t\"sellerUrl\": \"https://appyogi.com\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/one-chat-all-in-one-messenger/id1139742811?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"One App for all messaging services.\\n\\nWhatsApp, Facebook Messenger, Hangouts, Telegram, Skype, Slack, WeChat, Twitter, YahooChat, ICQ chat, HipChat, Discord, GroupMe, QQ, Facebook Page messenger VK, Fleep, RocketChat, MySMS, IRC Chat, TweetDeck Tinder.\\n\\nNote: One Chat is a wrapper app, combining all the messaging services. Experience will be 100% similar to web extension of those services, which extra features as follows. \\n\\n▸ QQ & WeChat only works for old users of them. \\n\\nFeatures:\\n▸ Schedule message to send them at a planned time. \\n▸ Send and receive Photos, Videos, doc, PDF..etc\\n▸ Use Multiple parallel accounts of the same service.\\n▸ Touch Bar support in 10.12 to select messaging services. \\n▸ Remember passwords for easy login. \\n▸ Get respective Notifications alerts and reply from the same.\\n▸ Auto Smart Gifs for messaging friends\\n▸ Mark all unread messages read with just one Click. \\n▸ Privacy mode to protect your messaging data with touch ID.\\n▸ Customize messaging service order in the side menu.\\n▸ FaceTime calling from WhatsApp & Telegram numbers.\\n▸ Customize notification as per your requirement.\\n▸ Shows notifications badges for individual services.\\n▸ Check if there are any unread messages, right in the menu bar.\\n▸ Go Full-screen! Chat with your friends, distraction-free in the full-screen mode.\\n▸ Lightweight all, with minimum installation size.\\n▸ Retina Display enabled icons\\n▸ Easy to use user-interface(UI) and user-experience(UX)\\n\\nUpcoming update:\\n- More chat services, suggestions most welcome.\\n- And much more.\\n\\n>>>>>>>> Download Now <<<<<<<<\\n\\nDisclaimer:\\nOne Chat is a third party App. The developer of this software is not affiliated with WhatsApp Inc. Facebook Inc. Telegram Inc. Slack Inc. Skype Inc. Google Inc. Atlassian Inc. Tencent Inc. Twitter Inc. V Kontakte. Yahoo Inc. Sleep Inc. Fleep Inc, RocketChat Inc., MySMS Inc, Tinder Inc., in any way.\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Social Networking\",\n\t\t\t\t\"Utilities\"\n\t\t\t],\n\t\t\t\"artistId\": 1039633008,\n\t\t\t\"artistName\": \"AppYogi Software\",\n\t\t\t\"price\": 19.99,\n\t\t\t\"bundleId\": \"com.appyogi.onechat\",\n\t\t\t\"version\": \"4.2\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/a3/09/1e/a3091e8d-c9fc-efdf-434c-3769715d2a3d/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple113/v4/8d/8d/6f/8d8d6fcc-5e7d-5978-9be7-2ce6a23b2810/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple113/v4/12/7a/7f/127a7f31-a9f9-b222-0d1b-c064065f5b65/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/72/84/81/7284818a-5bd3-0429-8658-b0038efbf67d/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/ef/bc/d7/efbcd7a7-3f1e-ba1f-2d55-bbba9b8c55f9/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/62/30/60/6230603f-7698-1cd7-9601-732a3ae74f8d/pr_source.jpg/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple124/v4/71/3e/2b/713e2ba7-0169-a4f2-b1c5-09252f5fcedd/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple124/v4/71/3e/2b/713e2ba7-0169-a4f2-b1c5-09252f5fcedd/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple124/v4/71/3e/2b/713e2ba7-0169-a4f2-b1c5-09252f5fcedd/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/swit-technologies-inc/id1451271780?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1464411410,\n\t\t\t\"trackName\": \"Swit - Team collaboration hub\",\n\t\t\t\"releaseDate\": \"2019-06-04T01:46:30Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6000\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.10.0\",\n\t\t\t\"primaryGenreName\": \"Business\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-09-01T04:58:09Z\",\n\t\t\t\"releaseNotes\": \"Updates\\n* UI/UX and performance improvements\\n \\nBug Fixes\\n* Other minor bug fixes\",\n\t\t\t\"primaryGenreId\": 6000,\n\t\t\t\"sellerName\": \"SWIT TECHNOLOGIES INC.\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Swit - Team collaboration hub\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"AM\",\n\t\t\t\t\"AR\",\n\t\t\t\t\"BN\",\n\t\t\t\t\"BG\",\n\t\t\t\t\"CA\",\n\t\t\t\t\"HR\",\n\t\t\t\t\"CS\",\n\t\t\t\t\"DA\",\n\t\t\t\t\"NL\",\n\t\t\t\t\"EN\",\n\t\t\t\t\"ET\",\n\t\t\t\t\"FI\",\n\t\t\t\t\"FR\",\n\t\t\t\t\"DE\",\n\t\t\t\t\"EL\",\n\t\t\t\t\"GU\",\n\t\t\t\t\"HE\",\n\t\t\t\t\"HI\",\n\t\t\t\t\"HU\",\n\t\t\t\t\"ID\",\n\t\t\t\t\"IT\",\n\t\t\t\t\"JA\",\n\t\t\t\t\"KN\",\n\t\t\t\t\"KO\",\n\t\t\t\t\"LV\",\n\t\t\t\t\"LT\",\n\t\t\t\t\"MS\",\n\t\t\t\t\"ML\",\n\t\t\t\t\"MR\",\n\t\t\t\t\"NB\",\n\t\t\t\t\"FA\",\n\t\t\t\t\"PL\",\n\t\t\t\t\"PT\",\n\t\t\t\t\"RO\",\n\t\t\t\t\"RU\",\n\t\t\t\t\"SR\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"SK\",\n\t\t\t\t\"SL\",\n\t\t\t\t\"ES\",\n\t\t\t\t\"SW\",\n\t\t\t\t\"SV\",\n\t\t\t\t\"TA\",\n\t\t\t\t\"TE\",\n\t\t\t\t\"TH\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"TR\",\n\t\t\t\t\"UK\",\n\t\t\t\t\"VI\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"106927881\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/swit-team-collaboration-hub/id1464411410?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Swit is one work suite for Chat and Project Management. With Swit, you can replace Slack and Trello (or Asana).\\n\\nSwit provides seamless workflows coupling chat and tasks in one convenient place. We have all the features that Slack and Trello (or Asana) have - faster, better, and safer.\\n\\n    * Team chat\\n    * Ideation post\\n    * To-do kanban\\n    * Gantt chart\\n    * Calendar\\n    * Advanced integrated search\\n\\nTechCrunch - “a collaboration suite that offers freedom from integrations”\\nBusiness Insider - “flexible enough to accommodate the needs of multiple departments within enterprises”\\nInfoTech - “one central hub to delineate a wide variety of processes”\\nSaaStock - \\\"Top 4 at the West Coast, Top 10 Rising Stars\\\"\\nFortune - “Swit, a San Francisco-based workplace team collaboration app, raised $6 million in funding.”\\nGSVlabs - “Now that everything is in one place it's easy to find conversations had in messages and relate them directly to project tasks.”\\nWeb Summit - “The Future of Team Collaboration Apps”\\n\\nSign up for FREE forever\\n\\nWork Sweet on Desktop and Mobile!\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Business\"\n\t\t\t],\n\t\t\t\"artistId\": 1451271780,\n\t\t\t\"artistName\": \"SWIT TECHNOLOGIES INC.\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.swit.desktop\",\n\t\t\t\"version\": \"2.9.9\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple123/v4/a5/e7/65/a5e765b9-6518-c932-fbed-db6d80828adf/pr_source.jpg/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/57/03/ec/5703ecf0-c694-9ccd-52c2-21d37b04e651/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/57/03/ec/5703ecf0-c694-9ccd-52c2-21d37b04e651/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/57/03/ec/5703ecf0-c694-9ccd-52c2-21d37b04e651/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/sai-praneeth/id1071875110?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1510447358,\n\t\t\t\"trackName\": \"Slacker - auto mouse mover\",\n\t\t\t\"releaseDate\": \"2020-06-10T07:00:00Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6002\",\n\t\t\t\t\"6000\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"$2.99\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.15\",\n\t\t\t\"primaryGenreName\": \"Utilities\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-06-11T04:47:14Z\",\n\t\t\t\"primaryGenreId\": 6002,\n\t\t\t\"sellerName\": \"Sai Praneeth\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Slacker - auto mouse mover\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"635428\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/slacker-auto-mouse-mover/id1510447358?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Do you work smart, not hard? Well that's great, but your boss and team mates might be forming opinions based on whether you show up as active or available or online on your office's instant messaging tools like Slack, Skype, Microsoft Teams and more. \\n\\nOnce you stay idle for some time, these messaging tools display your status as away or idle or offline causing your co-workers to suspect you are not in front of your computer all the time. You know how big a problem this is if you WFH (work from home) regularly and can't constantly be in front of your computer.\\n\\nSlacker solves this by moving your mouse pointer for you whenever you are idle - the result is that you always show as active on any corporate/office instant messaging tools (like Slack or Microsoft Teams) running on your work computer.\\n\\nThis additionally also means that your screen lock and screensaver will not be activated and your system will not go to sleep just because you step away from your computer while working from home or in the office.\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Utilities\",\n\t\t\t\t\"Business\"\n\t\t\t],\n\t\t\t\"artistId\": 1071875110,\n\t\t\t\"artistName\": \"Sai Praneeth\",\n\t\t\t\"price\": 2.99,\n\t\t\t\"bundleId\": \"com.inchwest.Slacker\",\n\t\t\t\"version\": \"1.3\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple118/v4/dd/49/f7/dd49f7b7-7cdd-183e-977f-369d2b638f5a/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple118/v4/9b/cf/e8/9bcfe870-f18b-73fd-4169-e4b32b7dba4f/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple118/v4/18/6f/40/186f4019-5989-3f71-6d9f-a0b01b906e1c/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple118/v4/e9/37/3e/e9373e04-c404-6ff4-05e2-a4f397aa090a/pr_source.jpg/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple118/v4/7c/fc/83/7cfc83aa-5d6a-b66f-233f-4e6e0da8cc79/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple118/v4/7c/fc/83/7cfc83aa-5d6a-b66f-233f-4e6e0da8cc79/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple118/v4/7c/fc/83/7cfc83aa-5d6a-b66f-233f-4e6e0da8cc79/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/qin-hu/id822142008?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1229446984,\n\t\t\t\"trackName\": \"MyTasks for Asana\",\n\t\t\t\"releaseDate\": \"2017-05-19T20:32:20Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6007\",\n\t\t\t\t\"6000\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"$4.99\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.10\",\n\t\t\t\"primaryGenreName\": \"Productivity\",\n\t\t\t\"currentVersionReleaseDate\": \"2018-01-07T20:48:30Z\",\n\t\t\t\"releaseNotes\": \"Minor bug fixes.\",\n\t\t\t\"primaryGenreId\": 6007,\n\t\t\t\"sellerName\": \"qin hu\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"MyTasks for Asana\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"330338\",\n\t\t\t\"sellerUrl\": \"https://enjoyableapps.wordpress.com/mytasks-for-asana\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/mytasks-for-asana/id1229446984?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"A native client for Asana on macOS.\\n\\nFEATURES\\n• Create tasks easily.\\n• View tasks from the menu-bar.\\n--- List of tasks assigned to you.\\n--- List of tasks you follow.\\n--- List of tasks in a project.\\n• Mark tasks as completed.\\n• Like and unlike a task.\\n• Comment on tasks.\\n• Get notifications when there are new tasks and updated tasks.\\n• Sort your tasks by due time, created time, updated time, or number of likes.\\n• Filter your tasks by projects, tags, or status.\\n\\nNOTE\\nMyTasks for Asana is a 3rd party application for Asana and is in no way endorsed or affiliated with Asana, Inc.\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Productivity\",\n\t\t\t\t\"Business\"\n\t\t\t],\n\t\t\t\"artistId\": 822142008,\n\t\t\t\"artistName\": \"qin hu\",\n\t\t\t\"price\": 4.99,\n\t\t\t\"bundleId\": \"com.huqin.MyTasks-for-Asana\",\n\t\t\t\"version\": \"1.6\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple123/v4/f4/65/99/f4659920-43c5-3cc1-036b-e569e5fddbcc/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/58/37/f4/5837f430-7748-62ea-f0b7-c4dce867ed8a/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple123/v4/a4/35/f1/a435f1fc-7ad0-8b09-c082-b514bdcb9033/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/55/dd/4b/55dd4be3-dce8-11c4-8916-97040fddd3b7/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple124/v4/90/f3/75/90f37528-b79d-0279-5362-4f0e47a354c9/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple124/v4/90/f3/75/90f37528-b79d-0279-5362-4f0e47a354c9/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple124/v4/90/f3/75/90f37528-b79d-0279-5362-4f0e47a354c9/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/ubergrape-gmbh/id943855716?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 971791845,\n\t\t\t\"trackName\": \"Grape - Messenger\",\n\t\t\t\"releaseDate\": \"2015-04-08T02:17:47Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6000\",\n\t\t\t\t\"6007\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.10.0\",\n\t\t\t\"primaryGenreName\": \"Business\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-07-17T17:13:52Z\",\n\t\t\t\"releaseNotes\": \"- Added support for Polish language.\",\n\t\t\t\"primaryGenreId\": 6000,\n\t\t\t\"sellerName\": \"UberGrape GmbH\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Grape - Messenger\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"AM\",\n\t\t\t\t\"AR\",\n\t\t\t\t\"BN\",\n\t\t\t\t\"BG\",\n\t\t\t\t\"CA\",\n\t\t\t\t\"HR\",\n\t\t\t\t\"CS\",\n\t\t\t\t\"DA\",\n\t\t\t\t\"NL\",\n\t\t\t\t\"EN\",\n\t\t\t\t\"ET\",\n\t\t\t\t\"FI\",\n\t\t\t\t\"FR\",\n\t\t\t\t\"DE\",\n\t\t\t\t\"EL\",\n\t\t\t\t\"GU\",\n\t\t\t\t\"HE\",\n\t\t\t\t\"HI\",\n\t\t\t\t\"HU\",\n\t\t\t\t\"ID\",\n\t\t\t\t\"IT\",\n\t\t\t\t\"JA\",\n\t\t\t\t\"KN\",\n\t\t\t\t\"KO\",\n\t\t\t\t\"LV\",\n\t\t\t\t\"LT\",\n\t\t\t\t\"MS\",\n\t\t\t\t\"ML\",\n\t\t\t\t\"MR\",\n\t\t\t\t\"NB\",\n\t\t\t\t\"FA\",\n\t\t\t\t\"PL\",\n\t\t\t\t\"PT\",\n\t\t\t\t\"RO\",\n\t\t\t\t\"RU\",\n\t\t\t\t\"SR\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"SK\",\n\t\t\t\t\"SL\",\n\t\t\t\t\"ES\",\n\t\t\t\t\"SW\",\n\t\t\t\t\"SV\",\n\t\t\t\t\"TA\",\n\t\t\t\t\"TE\",\n\t\t\t\t\"TH\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"TR\",\n\t\t\t\t\"UK\",\n\t\t\t\t\"VI\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"83490302\",\n\t\t\t\"sellerUrl\": \"https://www.grape.io/press/\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/grape-messenger/id971791845?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"A different messenger.\\nSecure video, voice and text conversations that happen inside your favourite business tools.\\n\\n- Real time messaging, file sharing, supporting private messages and group conversations.\\n- Run it inside your favourite tools like Jira, Confluence or Sharepoint.\\n- Reimagined Enterprise Search helps you quickly find anything within your business, including services, documents, appointments, files, contacts and more. \\n- Instantly synced across all devices.\\n- Configurable notifications for desktop, mobile push and email.\\n- Host it on-premises or in the secure Euro-Cloud\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Business\",\n\t\t\t\t\"Productivity\"\n\t\t\t],\n\t\t\t\"artistId\": 943855716,\n\t\t\t\"artistName\": \"UberGrape GmbH\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.ChatGrape\",\n\t\t\t\"version\": \"3.1.0\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple113/v4/ce/e2/9d/cee29db7-0202-ee16-2d5e-e3beb87323cc/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple113/v4/49/81/95/4981952e-c172-68ea-38ae-3c082539959e/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple123/v4/ff/3a/47/ff3a47e3-66a0-91fd-5777-9b58922c1af1/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/41/e8/d6/41e8d6e4-7ba0-ef42-08ec-bd0f6ecd20f7/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/2d/b5/b9/2db5b92b-3aeb-0bf2-5dc3-592c98be60b4/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/ed/b0/c4/edb0c40a-5bc3-c67d-1ef2-9a4aa5a0955d/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/3e/58/7c/3e587cf0-0400-7339-2add-96a7abd91e24/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/5e/9e/c5/5e9ec51a-b500-2da3-5d50-94c2e616b35e/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple124/v4/09/80/7f/09807fde-00e8-d19f-1a06-d20bbc9f967f/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple124/v4/09/80/7f/09807fde-00e8-d19f-1a06-d20bbc9f967f/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple124/v4/09/80/7f/09807fde-00e8-d19f-1a06-d20bbc9f967f/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/octopus-think/id1489816365?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1489816366,\n\t\t\t\"trackName\": \"Mic Drop.\",\n\t\t\t\"releaseDate\": \"2020-04-14T07:00:00Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6002\",\n\t\t\t\t\"6007\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"$6.99\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.15\",\n\t\t\t\"primaryGenreName\": \"Utilities\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-08-03T19:32:54Z\",\n\t\t\t\"releaseNotes\": \"We fixed a bug that could cause Mic Drop to crash/hang if you were using Loopback audio devices.\",\n\t\t\t\"primaryGenreId\": 6002,\n\t\t\t\"sellerName\": \"Octopus Think Ltd.\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Mic Drop.\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"1746857\",\n\t\t\t\"sellerUrl\": \"https://getmicdrop.com\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/mic-drop/id1489816366?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Ever been in a video call and needed to turn off your microphone, but couldn’t find the mute button quickly enough?\\n\\nMic Drop helps you mute (and then unmute!) your microphone with a keyboard shortcut or a menu bar control. It works with every meeting app out there—from Zoom to Slack, FaceTime to Houseparty.\\n\\nIt also shows your mic status in a menu bar icon, so you'll always know at a glance whether you're muted or not. And it lets you (un)mute yourself even if you don't have your meeting app open.\\n\\nMic Drop:\\n\\n- Allows you to define a custom keyboard shortcut that works across your Mac.\\n- Works with every app and audio device out there.\\n- Automatically keeps you muted (or unmuted!) if you change audio devices.\\n- Supports push-to-talk and push-to-mute.\\n- Shows your microphone status in the menu bar.\\n- Shows your microphone status in an optional floating window.\\n- Respects your privacy. Mic Drop never listens to you.\\n\\nBecause Mic Drop mutes your audio at the system level, it works with any app you can imagine. We’ve tested with:\\n\\n- Zoom\\n- Slack\\n- Google Meet\\n- Skype\\n- Microsoft Teams\\n- Discord\\n- FaceTime\\n- Vidyo\\n- Houseparty\\n- Cisco Webex\\n- and many more.\\n\\nIt just works. No matter where you’re meeting, Mic Drop’s got you covered.\\n\\n----------\\n\\nA note on hardware compatibility:\\n\\nMic Drop works with just about any audio device out there, but some audio devices can't be muted by macOS, so Mic Drop can't control them. All bluetooth and wired headphones work—it's just some niche USB audio interfaces that Mic Drop won't mute. Mic Drop will warn you if it detects an incompatible device. A list of problematic devices are listed on our support page.\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Utilities\",\n\t\t\t\t\"Productivity\"\n\t\t\t],\n\t\t\t\"artistId\": 1489816365,\n\t\t\t\"artistName\": \"Octopus Think\",\n\t\t\t\"price\": 6.99,\n\t\t\t\"bundleId\": \"com.octopusthink.Mic-Drop\",\n\t\t\t\"version\": \"1.1.6\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/85/61/24/85612409-4ed4-cffc-6df0-1f9cb8098019/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/13/53/65/13536517-9cc2-fe7a-5bcb-1dec9d887a8a/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple113/v4/d2/17/69/d217692c-c134-debd-d174-12ac27bd85e4/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/bf/38/40/bf3840b3-b4ab-b9ea-f9a3-ede48ad6c69a/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple123/v4/ae/8c/b5/ae8cb50b-e5ce-2f5c-5347-9b94759a704c/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple123/v4/b0/2f/ce/b02fce9a-f5bc-e9a6-b4e7-2d25a2876ca3/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/72/67/63/72676353-b09c-b71d-5a9d-f80765f9a5bd/pr_source.jpg/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/a8/b2/54/a8b254b7-9a2d-cef2-5d73-681b6edbd774/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/a8/b2/54/a8b254b7-9a2d-cef2-5d73-681b6edbd774/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/a8/b2/54/a8b254b7-9a2d-cef2-5d73-681b6edbd774/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/sdwr/id560094566?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 940239558,\n\t\t\t\"trackName\": \"Lists for Trello\",\n\t\t\t\"releaseDate\": \"2014-11-21T03:38:30Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6007\",\n\t\t\t\t\"6002\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"$4.99\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.14\",\n\t\t\t\"primaryGenreName\": \"Productivity\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-05-04T17:56:36Z\",\n\t\t\t\"releaseNotes\": \"- Performance and stability improvements\",\n\t\t\t\"primaryGenreId\": 6007,\n\t\t\t\"sellerName\": \"Alexey Linkov\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Lists for Trello\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"3385009\",\n\t\t\t\"sellerUrl\": \"https://lists4trello.com\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/lists-for-trello/id940239558?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Lists for Trello keeps you focused on current tasks. Toggle side panels and on-card indicators when you want more context and complexity.\\n\\n\\n* Edit, archive, move and add cards across your lists, start dragging a card to see options.\\n\\n* Edit, delete or rename lists and boards by right clicking on one of the list items on the left\\n\\n* You can switch between all cards and only those cards assigned to you across all boards. Use the Crown Switch located on the left pane. \\n\\n* Cards can be sorted by due date. You can turn off sorting, sort ascending or descending clicking on the stopwatch icon on the left pane.\\n\\n* Cards can be marked with a special dot. You can choose from several criteria that should be met for the dot to be displayed. By default dot is shown for cards that have open todos, you can change that by opening View -> Show Dot When... in the top app menu\\n\\n* Due and overdue cards are color coded in list view. Overdue colored red and due are colored amber.\\n\\n* Color labels for cards are displayed in center pane. Right click on a card to add  / remove labels. You can hide labels by going in Menu -> View -> Toggle Labels\\n\\n* Checklists and todo items for a card are accessible from right pane by flipping the switch on top. You can add, delete, rename and reorder todo items. You can click just once on a todo item to start editing it. Reordering of checklists as well as making a new card from a todo item will be available shortly.\\n\\n* Today widget\\nLeft click on a list in the main application and select \\\"Show in Today Widget.\\\" to add it.\\n\\nUseful shortcuts:\\n- CMD+R to reload cards in currently selected list\\n- SHIFT+CMD+R to reload all lists and boards\\n- CMD+1 to toggle sidebar\\n- CMD+0 to toggle card inspector\\n- CMD+L to toggle color labels on cards\\n\\nGive us feedback and see what features / fixes / improvements are coming in the next update by following us on https://www.facebook.com/lists4trello/\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Productivity\",\n\t\t\t\t\"Utilities\"\n\t\t\t],\n\t\t\t\"artistId\": 560094566,\n\t\t\t\"artistName\": \"SDWR\",\n\t\t\t\"price\": 4.99,\n\t\t\t\"bundleId\": \"SDWR.Lists\",\n\t\t\t\"version\": \"2.7\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple5/v4/d2/c3/92/d2c392c5-e08e-7df8-c433-a3b296a6650a/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple5/v4/02/78/4f/02784fb5-7afa-228b-7726-ddf2aaaa0b84/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple5/v4/46/10/45/4610450f-2868-bf20-17c6-b684c49c0c89/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple7/v4/eb/b4/da/ebb4dacc-5062-77f4-5c99-ac9ebdf6ff99/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple7/v4/46/2c/0f/462c0f28-f865-25ad-3164-df261a5c2760/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple30/v4/95/83/04/9583045a-665d-a0be-dfc7-89487890d35d/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple30/v4/95/83/04/9583045a-665d-a0be-dfc7-89487890d35d/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple30/v4/95/83/04/9583045a-665d-a0be-dfc7-89487890d35d/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/eric-delabar/id823959467?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 994537604,\n\t\t\t\"trackName\": \"ChannelScrobbler - Real-time scrobble bot for Last.fm/Slack\",\n\t\t\t\"releaseDate\": \"2015-06-01T17:54:13Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6005\",\n\t\t\t\t\"6011\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"$2.99\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.10\",\n\t\t\t\"primaryGenreName\": \"Social Networking\",\n\t\t\t\"currentVersionReleaseDate\": \"2016-07-06T01:11:45Z\",\n\t\t\t\"releaseNotes\": \"* Fixed bug where custom bot name was not saved between application launches.\\n* Fixed artist info lookup/sterilization so that if Last.fm lookup fails original scrobble info is displayed instead.\\n* Updated some metadata.\",\n\t\t\t\"primaryGenreId\": 6005,\n\t\t\t\"sellerName\": \"Eric DeLabar\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"ChannelScrobbler - Real-time scrobble bot for Last.fm/Slack\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"1202787\",\n\t\t\t\"sellerUrl\": \"https://ericdelabar.com/projects/channelscrobbler.html\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/channelscrobbler-real-time-scrobble-bot-for-last-fm-slack/id994537604?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"ChannelScrobbler is a fun way to post your Last.fm scrobbles to a Slack channel in real-time.  Create a music channel and show your friends and co-workers what you're listening to and see their favorites as well.  \\n\\nOther solutions like IFTTT poll the Last.fm feed and only update every 15 minutes or so, ChannelScrobbler allows you to choose your update period and see updates as frequently as every 30 seconds.  \\n\\nChannelScrobbler runs in your status bar and can launch on startup, so it's always there, listing every track you play.  Because ChannelScrobbler reads your Last.fm feed scrobbles from your account it will catch new songs from any device that supports scrobbling, not just your computer!\\n\\n* Includes retina graphics and support for dark status bars!\\n* Scrobbles are posted by a bot with customizable name, avatar, and colors.\\n\\nIf you're having problems using ChannelScrobbler, please email edelabar@gmail.com for support.\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Social Networking\",\n\t\t\t\t\"Music\"\n\t\t\t],\n\t\t\t\"artistId\": 823959467,\n\t\t\t\"artistName\": \"Eric DeLabar\",\n\t\t\t\"price\": 2.99,\n\t\t\t\"bundleId\": \"com.ericdelabar.ChannelScrobbler\",\n\t\t\t\"version\": \"1.2\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/PurpleSource114/v4/bf/08/c7/bf08c74c-2313-d6a8-183e-1d7c23cfada4/5f0c1b7d-ce2f-42dd-a389-5acb3df5d9e5_screen-1.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/PurpleSource124/v4/d6/e6/d3/d6e6d358-5a28-fe8a-5855-0c3e92fd92d1/6c770e65-6a0a-4ce1-a9a3-a88863128f9d_screen-2.png/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/PurpleSource124/v4/0e/5c/0b/0e5c0b2e-24d0-fa91-2abc-a2141e059de9/af39f6ac-209e-434d-bc40-fe9262be4198_screen-3.png/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/PurpleSource124/v4/2b/de/5e/2bde5e2e-cb46-4fe6-2ff4-e5487d2d4d35/0d7ddd32-f5ff-4253-8cd8-14170809d8d1_screen-4.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple114/v4/84/e6/cd/84e6cd75-70ce-7146-7e2b-eca3c014bfb4/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple114/v4/84/e6/cd/84e6cd75-70ce-7146-7e2b-eca3c014bfb4/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple114/v4/84/e6/cd/84e6cd75-70ce-7146-7e2b-eca3c014bfb4/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/ilya-shaisultanov/id1155364065?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1524355453,\n\t\t\t\"trackName\": \"Thinking Face Emoji Tools\",\n\t\t\t\"releaseDate\": \"2020-07-24T07:00:00Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6005\",\n\t\t\t\t\"6002\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.12\",\n\t\t\t\"primaryGenreName\": \"Social Networking\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-08-12T21:08:41Z\",\n\t\t\t\"releaseNotes\": \"Save options across reloads.\",\n\t\t\t\"primaryGenreId\": 6005,\n\t\t\t\"sellerName\": \"Ilya Shaisultanov\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Thinking Face Emoji Tools\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"3757555\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/thinking-face-emoji-tools/id1524355453?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Tools that make life as a Slack emoji addict a little easier.\\n\\nFeatures:\\n• Drag & drop emoji upload\\n• Bulk emoji deletion\\n• Optional prefix and suffix for emoji names\\n• Automatically overwrite existing emoji \\n• Respect Slack API rate limiting\\n\\nEver wanted to upload 100 emoji to slack in one fell swoop? Now you can!\\n\\n1. Install this extension\\n2. Go to your Slack's /customize/emoji page\\n3. Drag and drop your emoji image files into the new \\\"Bulk Emoji Uploader\\\". File names become the emoji name, e.g. meow-party.gif becomes :meow-party: Customize them with an optional prefix or suffix!\\n4. You've now got a whole lotta emoji!\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Social Networking\",\n\t\t\t\t\"Utilities\"\n\t\t\t],\n\t\t\t\"artistId\": 1155364065,\n\t\t\t\"artistName\": \"Ilya Shaisultanov\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.diversario.Thinking-Face-Emoji-Tools\",\n\t\t\t\"version\": \"1.3.1\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple123/v4/a5/aa/c5/a5aac5fd-8acc-bc30-47aa-3243d9a37a15/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple123/v4/89/a0/2c/89a02cfc-d14b-b789-b015-a1611bbd322f/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/61/70/03/6170030f-69b1-33f6-f59e-890d8bbbf648/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/40/1a/c0/401ac066-772a-01df-e339-2aee5e9cc919/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/41/40/5d/41405d96-802f-7f56-54ca-3bea7ce9c715/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple113/v4/ae/a9/eb/aea9eb7c-b4ab-97e0-3f5d-8881bc65ad67/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple113/v4/ae/a9/eb/aea9eb7c-b4ab-97e0-3f5d-8881bc65ad67/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple113/v4/ae/a9/eb/aea9eb7c-b4ab-97e0-3f5d-8881bc65ad67/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/uptech-works-llc/id1190352695?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1487662886,\n\t\t\t\"trackName\": \"TeamSmash\",\n\t\t\t\"releaseDate\": \"2020-01-07T08:00:00Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6007\",\n\t\t\t\t\"6005\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.14\",\n\t\t\t\"primaryGenreName\": \"Productivity\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-04-20T17:00:26Z\",\n\t\t\t\"releaseNotes\": \"Your team now has more control over when snapshots are taken!\\n\\n• Opt into manual capture mode to receive a notification as often as you want to remind you to snap a fun photo for your team! Your picture will not be taken automatically. Snap only when you want to!\\n• For those of you with automatic capture turned on, you can also receive notifications right before your photo is taken. A perfect reminder to put on that fancy smile, a ridiculous face, or stop the photo altogether. Your choice!\\n\\nDon't forget, you can always change your capture mode and other settings by going to TeamSmash preferences menu! Oh, and we made some bug fixes and performance enhancements too.\",\n\t\t\t\"primaryGenreId\": 6007,\n\t\t\t\"sellerName\": \"UpTech Works, LLC\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"TeamSmash\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"5512772\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/teamsmash/id1487662886?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"TeamSmash is a companion app for Slack that lets you use video snapshots to enhance your remote working experience. \\n\\nQuickly see when your teammates are around and available to ask questions - or when they are away from their desk. \\n\\nYou can either take a picture of yourself manually or have the app take one automatically every so often. \\n\\nAnd if you need to jump into a video call, it's easy to start a Slack call with one of your co-workers. You are in complete control! \\n\\nBest of all, you can also use the built-in feed to memorialize any of your teammates with a funny meme of their picture. \\n\\nWorking remote should not feel lonely. Use TeamSmash and feel connected to your team!\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Productivity\",\n\t\t\t\t\"Social Networking\"\n\t\t\t],\n\t\t\t\"artistId\": 1190352695,\n\t\t\t\"artistName\": \"UpTech Works, LLC\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"ch.upte.TeamSmash.mac\",\n\t\t\t\"version\": \"1.2.0\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/8c/b8/6e/8cb86e19-7cea-205b-af78-b61242766400/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple123/v4/64/f9/2f/64f92f39-6690-a3e1-c7ff-50978b750431/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/d4/e4/bb/d4e4bbf4-44ef-f844-5efa-f9a720f57c6e/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/cc/22/1c/cc221c0c-6e03-222e-e702-206afba31408/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/31/c6/24/31c6242f-5899-c99d-8062-89ce18beb2b0/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/e1/a2/fc/e1a2fc62-61aa-04cb-82aa-14ac07909a1e/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple124/v4/c7/15/b6/c715b687-7bd2-0fe5-3f61-43cad60b4b04/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple124/v4/c7/15/b6/c715b687-7bd2-0fe5-3f61-43cad60b4b04/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple124/v4/c7/15/b6/c715b687-7bd2-0fe5-3f61-43cad60b4b04/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/simply-good-software/id385251756?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1499496939,\n\t\t\t\"trackName\": \"Pyrus\",\n\t\t\t\"releaseDate\": \"2020-06-11T07:00:00Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6000\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.10.0\",\n\t\t\t\"primaryGenreName\": \"Business\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-08-20T13:59:50Z\",\n\t\t\t\"releaseNotes\": \"Minor bug fixes.\",\n\t\t\t\"primaryGenreId\": 6000,\n\t\t\t\"sellerName\": \"Simply Good Software, Inc\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Pyrus\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\",\n\t\t\t\t\"RU\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"80176195\",\n\t\t\t\"sellerUrl\": \"https://pyrus.com/en\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/pyrus/id1499496939?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Pyrus is the team communication tool for your entire business. It incorporates real-time messaging, task delegation, and approval flows. Finally, all your tasks and conversations are in one easy-to-use interface.\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Business\"\n\t\t\t],\n\t\t\t\"artistId\": 385251756,\n\t\t\t\"artistName\": \"Simply Good Software\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"net.pyrus.macosclient\",\n\t\t\t\"version\": \"1.0.12\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple123/v4/b8/57/43/b85743bc-16b6-4971-02dd-5b7c2162b5e3/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple123/v4/81/70/f5/8170f593-ad4e-f377-17b3-ab0c30c279a2/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple123/v4/72/ae/78/72ae7824-f4a0-4f3b-27e3-656c358e877a/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple113/v4/f9/a9/26/f9a92636-e348-78c2-e00f-c04d8e319637/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple123/v4/dd/c0/f7/ddc0f790-b7a5-cebd-30f2-4f55a1d73068/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/6d/5d/d5/6d5dd50e-7a42-8f3b-0c99-f3defe3d153f/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple123/v4/b2/a8/9e/b2a89eaf-2c84-43b5-013b-29450ee5686d/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/50/03/83/50038321-48f9-3087-b698-733047b17969/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple123/v4/dd/25/5b/dd255b82-3e85-0a1f-768b-0e0787f846f7/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple123/v4/67/f1/7d/67f17dbf-9832-01c0-98d7-03e91320de8d/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple123/v4/67/f1/7d/67f17dbf-9832-01c0-98d7-03e91320de8d/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple123/v4/67/f1/7d/67f17dbf-9832-01c0-98d7-03e91320de8d/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/intrinsic-properties-llc/id1119328387?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1438864470,\n\t\t\t\"trackName\": \"Monitro\",\n\t\t\t\"releaseDate\": \"2019-10-21T07:00:00Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6002\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.14\",\n\t\t\t\"primaryGenreName\": \"Utilities\",\n\t\t\t\"currentVersionReleaseDate\": \"2019-12-08T01:45:12Z\",\n\t\t\t\"releaseNotes\": \"Minor bug fixes\",\n\t\t\t\"primaryGenreId\": 6002,\n\t\t\t\"sellerName\": \"Intrinsic Properties, LLC\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Monitro\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"14008794\",\n\t\t\t\"contentAdvisoryRating\": \"17+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/monitro/id1438864470?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"17+\",\n\t\t\t\"description\": \"Monitro is a macOS menu bar app that monitors folders for changes and can also provide simple IMAP mail processing as well.\\n\\nFor folders you create a list of folders you wish to have monitored. You can select details such as search depth and whether or not aliases should be followed. You can then apply a wide variety of timers to do the comparisons for changes ranging from every minute to something like weekly on Thursday at 2:30 PM. When changes are detected you can send a change report to combination of email addresses, a Slack web hook, or log file. Change detections are based on comparing to a database of file names, created dates, and modified dates. Using a database is important since you can actually quit the app and launch it any time in the future and it will report on any changes since it last saw the folders being monitored at the next reporting times.\\n\\nFor IMAP email processing you can apply simple rules to any email accounts you want to be monitored. You can query on To, From, CC, BCC, Subject, Body, Has Attachment, Attachment Name, Attachment Type, and for PDF or text files look at text within the attachment itself. When an email is matched you can apply actions on it such as Move, Copy, Delete, Mark Read, Mark Flagged, Mark Answered, or Save Attachments. It is important to note that you can actually Move or Copy messages between completely different IMAP accounts you have defined for access. It is usually very difficult to find these features server side and though some are possible client side with Monitro you do not need to have an email client running 24/7 to provide this level of filtering.\\n\\nMonitro is FREE for one Folder Monitor and one IMAP Monitor Rule. If you need more than that you can purchase a yearly subscription for $12.99 to unlock Full Access mode which let you run an unlimited number of monitors for folders or rules for IMAP accounts. If $12.99 seems high remember this is a very specific use app that is intended to unlock more time if your life if you find its features useful. It is not expected to attract a large paid user base. However, if the user base proves large enough the targeted use of funds is further feature development based on user feedback.\\n\\nMonitro is made for Mojave will not work on earlier versions of macOS.   Unless you are saving attachments from IMAP accounts the only writing to your file system Monitro will do is to its own private settings and databases. It will not touch or otherwise store any information in the folders you monitor thus it is possible to have more than one monitor for a single folder and still have things work flawlessly. Monitro is made to play well as a sandboxed app but if you are looking to monitor folders applications normally do not have access to you will need to enable Full Disk Access on your own.\\n\\nHINT: For IMAP Rules saving attachments Monitro pairs perfectly with Haze from Noodlesoft. Hazel is an app from an unrelated developer that watches whatever folders you tell it to, automatically organizing your files according to the rules you create.\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Utilities\"\n\t\t\t],\n\t\t\t\"artistId\": 1119328387,\n\t\t\t\"artistName\": \"Intrinsic Properties, LLC\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.intrinsicproperties.Monitro\",\n\t\t\t\"version\": \"1.0.3\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple118/v4/d6/65/04/d66504d2-cde6-9e4f-539b-ed1cd6396003/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple118/v4/81/b0/da/81b0da6c-f104-4c1f-6310-ed260f8001e1/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple118/v4/88/16/d5/8816d503-8827-169a-e5ee-604b2fc08ea4/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple118/v4/5f/7d/f5/5f7df55b-0660-0efc-087c-8940fa6db518/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple118/v4/55/55/32/55553228-0460-37bd-92ed-4631c52e9583/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple118/v4/f1/81/0a/f1810a36-68e2-fd1b-31dd-a9f1db88b344/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple118/v4/f1/81/0a/f1810a36-68e2-fd1b-31dd-a9f1db88b344/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple118/v4/f1/81/0a/f1810a36-68e2-fd1b-31dd-a9f1db88b344/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/vm-mobile-team/id646128457?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1421835215,\n\t\t\t\"trackName\": \"Checkers ◦\",\n\t\t\t\"releaseDate\": \"2018-08-09T06:24:05Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6014\",\n\t\t\t\t\"7004\",\n\t\t\t\t\"7012\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"$1.99\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.11\",\n\t\t\t\"primaryGenreName\": \"Games\",\n\t\t\t\"currentVersionReleaseDate\": \"2018-12-13T19:07:37Z\",\n\t\t\t\"releaseNotes\": \"Bug fixes and performance improvements\",\n\t\t\t\"primaryGenreId\": 6014,\n\t\t\t\"sellerName\": \"VM Mobile Team\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Checkers ◦\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"36743790\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/checkers/id1421835215?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Checkers is the timeless game which has delighted young and old alike for thousands of years. At the same time both simple and complex, it has survived despite the popularity of other game genres and is played by thousands of people. \\n\\nThis powerful app can be enjoyed with family and friends or on your own, and has different settings to suit your preferences. \\n\\nIts unique, uncluttered design gives the game a realistic look and feel, evoking memories of the checkers you used to play as a child, and thanks to its fast AI you will forget that you’re playing against a program.\\n\\nKey features:\\n- Games against computer (4 levels, color option)\\n- 2 players game with time limit\\n- Nice look and feel\\n- Undo\\n- Save/load unfinished game\\n- Timer based game\\n\\nYou will also gain experience points by winning against the AIs (+1 for Easy, +3 for Medium, +5 for Hard, +7 for Very Hard).\\n\\nA must have if you like strategic board games.\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Games\",\n\t\t\t\t\"Board\",\n\t\t\t\t\"Puzzle\"\n\t\t\t],\n\t\t\t\"artistId\": 646128457,\n\t\t\t\"artistName\": \"VM Mobile Team\",\n\t\t\t\"price\": 1.99,\n\t\t\t\"bundleId\": \"com.vm.osx.checkersus\",\n\t\t\t\"version\": \"127\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/91/8f/e3/918fe3cc-f08b-910e-7cc8-e78fd2f700e1/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple123/v4/4c/8a/88/4c8a884e-d6c2-4149-0064-aeafe9d05fb7/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple123/v4/4c/8a/88/4c8a884e-d6c2-4149-0064-aeafe9d05fb7/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple123/v4/4c/8a/88/4c8a884e-d6c2-4149-0064-aeafe9d05fb7/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/recursive-illusions/id1502073675?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1502073676,\n\t\t\t\"trackName\": \"Boss Alert\",\n\t\t\t\"releaseDate\": \"2020-04-18T07:00:00Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6002\",\n\t\t\t\t\"6007\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.14\",\n\t\t\t\"primaryGenreName\": \"Utilities\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-04-22T03:57:16Z\",\n\t\t\t\"releaseNotes\": \"Added a fix for SnapCamera.\",\n\t\t\t\"primaryGenreId\": 6002,\n\t\t\t\"sellerName\": \"Recursive Illusions LLP\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Boss Alert\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"27606231\",\n\t\t\t\"sellerUrl\": \"https://bossalert.app\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/boss-alert/id1502073676?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Boss Alert uses the webcam to detect if someone is standing behind you. The moment someone walks in behind you, it will automatically open a work related app (eg. Excel, Word). \\n\\n100% Privacy!\\n\\n- Boss Alert uses your webcam to keep a watch behind your back.\\n- But rest assured, we don't store your video anywhere (Not even on your own device).\\n- We don't collect or send any info about which apps or how long do you use them.\\nIt will always be like this!\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Utilities\",\n\t\t\t\t\"Productivity\"\n\t\t\t],\n\t\t\t\"artistId\": 1502073675,\n\t\t\t\"artistName\": \"Recursive Illusions\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.recursiveillusions.bossalert\",\n\t\t\t\"version\": \"1.1\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/81/55/c6/8155c614-6ddc-dd5b-ca40-bfa4689acb30/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/c2/4f/04/c24f0450-b95e-4807-07c8-0d1c27058401/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple123/v4/aa/e6/24/aae624a4-989e-8cd5-c020-04188adf6dfc/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/db/a0/93/dba093b9-421d-d04c-f2d5-dccad85a7dfb/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/c4/4f/78/c44f7880-0400-313f-2b46-2bd366a41a8b/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/2c/01/05/2c0105a2-8fe5-7e47-fe89-64855de1cbb8/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/6a/3d/4b/6a3d4b7e-e567-4f8b-2db2-1a16ca35da12/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple123/v4/94/99/15/949915ad-a4b1-47f6-66ab-11c2e3054897/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple123/v4/7d/42/70/7d42703f-fa1b-8436-e8f6-9297c4e16138/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/d2/fd/fe/d2fdfe77-3210-eae4-8454-d168935eb1cc/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/14/cd/6f/14cd6fac-4bdf-5344-da46-88fd95be187d/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/14/cd/6f/14cd6fac-4bdf-5344-da46-88fd95be187d/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/14/cd/6f/14cd6fac-4bdf-5344-da46-88fd95be187d/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/cogoo-inc/id951657514?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1447215756,\n\t\t\t\"trackName\": \"World of Mines!\",\n\t\t\t\"releaseDate\": \"2018-12-22T12:12:25Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6014\",\n\t\t\t\t\"7012\",\n\t\t\t\t\"7004\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"$1.99\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.5.0\",\n\t\t\t\"primaryGenreName\": \"Games\",\n\t\t\t\"currentVersionReleaseDate\": \"2019-11-01T01:33:07Z\",\n\t\t\t\"releaseNotes\": \"- PMA Tournament System Open!!\\n- Enjoy special nation package.(Spain, Korea, United Kingdom).\",\n\t\t\t\"primaryGenreId\": 6014,\n\t\t\t\"sellerName\": \"Cogoo Inc.\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"World of Mines!\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"36325933\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/world-of-mines/id1447215756?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"World of Mines is a classic, throwback PC game with a World Map twist. \\nInspired by the original game written for many computing platforms since the 1960s. \\n\\nCOGOO INITIATIVE\\nTeam Cogoo has created World of Mines as a small and humble campaign to help promote 2025 Completion Challenge and to raise awareness in our community. Whether you have 10 minutes, one hour, or plenty of time, you can help build  a world free of land mines and promote the rights of landmine victims too! \\n\\nTHE WORLD IS STILL IN DANGER OF LANDMINES\\nThe use of land mine is controversial because of their potential as indiscriminate weapons. They can remain dangerous many years after a conflict has ended, harming civilians and the economy. 78 countries are contaminated with land mines and 15000+ people are killed every year. Approximately 80% of land mine casualties are civilian, with children as the most affected age group. Most Killings occur in times of peace. \\n\\nIf you like old classic games such as chess, checkers, backgammon, solitaire, freecell as well as classic puzzle games like sudoku, tetris and crossword puzzles then this game is for you!\\n\\nGAME PLAY\\n-Save the world from landmines by finding bombs\\n-Easy to control \\n-Best, smoothest, fastest interface of any Mines game\\n-First tap luck\\n-Flag Mode: Turn on flag mode to mark tiles you think are bombs quickly\\n-177 Countries for hours of fun. (Countries and number of bombs don’t necessarily have a meaning)\\n-Variety of map sizes and shapes\\n\\nHOW TO PLAY\\nThe objective of the game is to clear a country map containing hidden “mines” or bombs without detonating any of them, with help from clues about the number or neighboring mines in each field. The player is initially presented with a world map. The Player can select and choose to play a specific country by touching the country on the map. The game is played by revealing squares of the grid by touching each square. If a square containing a mine is revealed, the player loses the game. If no mine is revealed, a digit is instead displayed in the square, indicating how many adjacent squares contains mines. If no mines are adjacent, the square becomes blank, and all adjacent squares will be recursively revealed. The player uses this information to deduce the contents of other squares, and may either safely reveal each square or mark the square as containing a mine. \\n\\nIf you love the game and care to provide feedback, please join our Facebook group and share you thoughts on future improvements.\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Games\",\n\t\t\t\t\"Puzzle\",\n\t\t\t\t\"Board\"\n\t\t\t],\n\t\t\t\"artistId\": 951657514,\n\t\t\t\"artistName\": \"Cogoo Inc.\",\n\t\t\t\"price\": 1.99,\n\t\t\t\"bundleId\": \"com.cogooland.minesweepermac\",\n\t\t\t\"version\": \"1.9.0\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple114/v4/fe/31/df/fe31df46-a337-8bec-d7e2-b40d2f555d8f/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple124/v4/bf/0c/df/bf0cdff1-32bc-bbad-054f-58cd41dd1929/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple114/v4/cf/c9/78/cfc978e8-f95b-0c23-3125-aeb0fdc74a85/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple124/v4/cf/22/c5/cf22c5dd-3daf-0afa-0388-a3b1856a4ba8/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple114/v4/fd/6c/a5/fd6ca5f4-2baa-cc0a-dd34-0962273a0307/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple124/v4/3a/a4/5a/3aa45a85-b305-92b0-59dc-989aa078c24c/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple114/v4/42/d4/f2/42d4f24e-3031-fb1e-33d6-9a2a6a866b52/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/9d/0d/c2/9d0dc254-4cb7-a464-f76a-4ea62d4d56ad/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/9d/0d/c2/9d0dc254-4cb7-a464-f76a-4ea62d4d56ad/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/9d/0d/c2/9d0dc254-4cb7-a464-f76a-4ea62d4d56ad/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/crystaly-k-k/id380628262?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1342613155,\n\t\t\t\"trackName\": \"Quetie for Qiita:Team\",\n\t\t\t\"releaseDate\": \"2019-03-03T21:13:12Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6026\",\n\t\t\t\t\"6007\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.13\",\n\t\t\t\"primaryGenreName\": \"Developer Tools\",\n\t\t\t\"currentVersionReleaseDate\": \"2019-03-04T00:11:47Z\",\n\t\t\t\"releaseNotes\": \"- Refine default width of content list\",\n\t\t\t\"primaryGenreId\": 6026,\n\t\t\t\"sellerName\": \"CRYSTALY, K.K.\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Quetie for Qiita:Team\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\",\n\t\t\t\t\"JA\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"6666830\",\n\t\t\t\"sellerUrl\": \"https://crystaly.com\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/quetie-for-qiita-team/id1342613155?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Quetie is Qiita:Team Viewer for Mac.\\n\\nOrganized Tags\\n・Slash-separated tags will be displayed hierarchically. You can reach the target tags even if your team has many tags.\\n\\nSearch\\n・Search with considering the high relevance and the newness of articles to reach the target.\\n\\nOpen Quickly\\n・Just type a few letters to open articles, tags, and users quickly.\\nEven if there are orthographical variants, it suggests some candidates.\\n\\nMultiple Teams\\n・Quetie supports multiple teams so that you can switch teams quickly.\\n\\nDark Mode\\n・It stands beautifully even in Dark Mode of macOS Mojave.\\n\\nDesigned exclusively for Mac.\\n・Drop to Open\\n・AirDrop\\n・Sharing Menu\\n・Touch Bar\\n・Customize Toolbar\\n・Drag & Drop\\n・Keychain\\n・Service Menu\\n\\n--------------------------------------------------\\n\\n【Subcription】\\nQuetie requires a subscription. \\n\\nDuration and price of each subscription are displayed in Quetie’ storefront, updated at the time of purchase. Payment will be charged to iTunes account at confirmation of purchase. \\n\\nTerms of Use and Privacy Policy\\nhttps://crystaly.com/terms/\\nhttps://crystaly.com/privacy/\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Developer Tools\",\n\t\t\t\t\"Productivity\"\n\t\t\t],\n\t\t\t\"artistId\": 380628262,\n\t\t\t\"artistName\": \"CRYSTALY, K.K.\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.crystaly.qiity\",\n\t\t\t\"version\": \"1.2.1\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/PurpleSource114/v4/b2/01/17/b2011751-bd84-c2f9-b7aa-f7ff1eb39863/0e4f5b87-361b-4955-a49f-e45a2f92288f_Email_signature.png/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/PurpleSource114/v4/86/49/13/86491346-1a25-fc2d-4eb6-56d207f6bdad/565c8234-7a2d-49f1-8d69-53447422e74a_simple_signature.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple114/v4/34/91/05/34910508-058d-2ccc-05a3-142d4baa5d32/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple114/v4/34/91/05/34910508-058d-2ccc-05a3-142d4baa5d32/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple114/v4/34/91/05/34910508-058d-2ccc-05a3-142d4baa5d32/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/gilbert-philippe-andze-tsoungui/id1444832950?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1444833191,\n\t\t\t\"trackName\": \"Email Signature Generator\",\n\t\t\t\"releaseDate\": \"2018-12-03T02:43:00Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6000\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"$4.99\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.10\",\n\t\t\t\"primaryGenreName\": \"Business\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-08-04T19:08:35Z\",\n\t\t\t\"releaseNotes\": \"-app resizing bug fixed\\n-design improved\\n-new email signature template\",\n\t\t\t\"primaryGenreId\": 6000,\n\t\t\t\"sellerName\": \"Gilbert Philippe Andze Tsoungui\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Email Signature Generator\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"3344757\",\n\t\t\t\"sellerUrl\": \"https://www.youtube.com/watch?v=7VNcde5-dCE&feature=youtu.be\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/email-signature-generator/id1444833191?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Building your HTML email signature is as simple as filling a form. It is super simple to use. If you have ever filled an online form, you know how to use this app.\\n\\nThe app has a simple way to build your email signature; you click your desired icon and then fill the form. \\n\\nThat how you do to fill your name, contact info, social media link ...\\n\\nYou can expect the HTML signature code generated by Email Signature Generator to work with all email clients\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Business\"\n\t\t\t],\n\t\t\t\"artistId\": 1444832950,\n\t\t\t\"artistName\": \"Gilbert Philippe Andze Tsoungui\",\n\t\t\t\"price\": 4.99,\n\t\t\t\"bundleId\": \"COM.GILBERT.Email-Signature\",\n\t\t\t\"version\": \"2.0\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple113/v4/51/2a/47/512a4708-fb83-e3ec-161a-eb2e8d3693cf/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple123/v4/25/e7/12/25e71218-6b69-067a-5c4e-2651a9ce2862/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/1d/29/4e/1d294e20-0044-eec3-4cf4-807e81fc337c/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/d3/40/29/d3402954-39d9-3d9a-bec8-6efa55b695d6/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple113/v4/ce/68/b0/ce68b073-4fb0-283e-b7c6-64e546e19681/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple113/v4/ce/68/b0/ce68b073-4fb0-283e-b7c6-64e546e19681/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple113/v4/ce/68/b0/ce68b073-4fb0-283e-b7c6-64e546e19681/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/health-science-inc/id1403957258?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1498500983,\n\t\t\t\"trackName\": \"LEON - a wellness app\",\n\t\t\t\"releaseDate\": \"2020-04-16T07:00:00Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6013\",\n\t\t\t\t\"6020\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.15\",\n\t\t\t\"primaryGenreName\": \"Health & Fitness\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-04-16T18:51:42Z\",\n\t\t\t\"primaryGenreId\": 6013,\n\t\t\t\"sellerName\": \"HEALTH SCIENCE INC\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"LEON - a wellness app\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"3413634\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/leon-a-wellness-app/id1498500983?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"LEON gives you access to the best studios and gyms, health risk assessments, wellness recommendations, and a cutting edge gamification engine. Seamlessly book classes, buy memberships, and schedule events.\\n\\nIf your employer uses LEON, you can easily connect to receive your corporate wellness benefits.\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Health & Fitness\",\n\t\t\t\t\"Medical\"\n\t\t\t],\n\t\t\t\"artistId\": 1403957258,\n\t\t\t\"artistName\": \"Health Science Inc\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"maccatalyst.co.myleon.app\",\n\t\t\t\"version\": \"1.6.4\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple128/v4/0f/07/d9/0f07d94c-3abf-5551-300b-f707258e4a8d/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple128/v4/f4/fd/d9/f4fdd9f6-c1ec-e6ff-eff0-15a95501d8ce/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple128/v4/78/ef/26/78ef2601-6cf0-061a-406a-c9aafc728f78/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple128/v4/19/97/f5/1997f51d-ac6a-bd59-73b7-40553031f5b6/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple128/v4/0e/80/ef/0e80effc-877d-5f0e-0b0c-20fe888db831/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple128/v4/0e/80/ef/0e80effc-877d-5f0e-0b0c-20fe888db831/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple128/v4/0e/80/ef/0e80effc-877d-5f0e-0b0c-20fe888db831/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/vm-mobile-team/id646128457?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1409316060,\n\t\t\t\"trackName\": \"Chinese Chess Q\",\n\t\t\t\"releaseDate\": \"2018-08-27T05:25:40Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6014\",\n\t\t\t\t\"6016\",\n\t\t\t\t\"7004\",\n\t\t\t\t\"7012\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"$1.99\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.11\",\n\t\t\t\"primaryGenreName\": \"Games\",\n\t\t\t\"currentVersionReleaseDate\": \"2018-09-28T22:28:16Z\",\n\t\t\t\"releaseNotes\": \"Bug fixes and performance improvements\",\n\t\t\t\"primaryGenreId\": 6014,\n\t\t\t\"sellerName\": \"VM Mobile Team\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Chinese Chess Q\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"38509169\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/chinese-chess-q/id1409316060?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Xiangqi (象棋) also called Chinese Chess, is a strategy board game for two players. It is one of the most popular board games in China and Vietnam, and is in the same family as Western (or international) chess. \\n\\nThe game represents a battle between two armies, with the object of capturing the enemy's general.\\n\\nChinese Chess Q brings this great game to your Mac. You can enjoy Chinese Chess in family game time, or you can also enjoy the game by playing with the AIs of varying difficulties. Beware that it is very challenging to beat the best AI in this game!\\n\\nYou will also gain experience points by winning against the AIs (+1 for Easy, +3 for Medium and +5 for Hard).\\n\\nFeatures:\\n* Undo\\n* Save/load unfinished game\\n* AIs with 4 levels of difficulties\\n* Timer based game\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Games\",\n\t\t\t\t\"Entertainment\",\n\t\t\t\t\"Board\",\n\t\t\t\t\"Puzzle\"\n\t\t\t],\n\t\t\t\"artistId\": 646128457,\n\t\t\t\"artistName\": \"VM Mobile Team\",\n\t\t\t\"price\": 1.99,\n\t\t\t\"bundleId\": \"com.vm.osx.xiangqi\",\n\t\t\t\"version\": \"120\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple124/v4/8e/70/22/8e70229f-a046-3a96-60d0-9de4760d9e87/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple124/v4/56/bc/02/56bc0215-09d3-e345-7ccb-6e7fb332f7b6/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/57/ee/09/57ee09ff-2a7e-96e0-dfbe-c7c47a0a386c/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/57/ee/09/57ee09ff-2a7e-96e0-dfbe-c7c47a0a386c/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/57/ee/09/57ee09ff-2a7e-96e0-dfbe-c7c47a0a386c/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/rene-rosendahl/id652634280?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1449437805,\n\t\t\t\"trackName\": \"TeamTimes\",\n\t\t\t\"releaseDate\": \"2019-02-01T14:17:26Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6007\",\n\t\t\t\t\"6000\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"$2.99\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.13\",\n\t\t\t\"primaryGenreName\": \"Productivity\",\n\t\t\t\"currentVersionReleaseDate\": \"2019-04-21T19:04:14Z\",\n\t\t\t\"releaseNotes\": \"- Meeting duration can now be selected\\n- Ability to add contacts from your Mac address book\\n- Data is saved automatically at a regular interval\\n- Avatar/image can be removed\\n- Fixes for sorting and column sizing and tabbing behavior\\n- Email address is checked for valid format\",\n\t\t\t\"primaryGenreId\": 6007,\n\t\t\t\"sellerName\": \"Rene Rosendahl\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"TeamTimes\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"4049495\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/teamtimes/id1449437805?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Are you working with a distributed team? Trouble keeping track of everyone's time zone and scheduling meetings? TeamTimes can help!\\n\\n- Track all team members with locations.\\n- See everyone’s contact info and local time.\\n- Find times that work in everyone’s time zones.\\n- Schedule meetings right from within the application.\\n- Trigger emails to selected team members.\\n- Add members right from your address book.\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Productivity\",\n\t\t\t\t\"Business\"\n\t\t\t],\n\t\t\t\"artistId\": 652634280,\n\t\t\t\"artistName\": \"Rene Rosendahl\",\n\t\t\t\"price\": 2.99,\n\t\t\t\"bundleId\": \"Rene-Rosendahl.TeamTimes\",\n\t\t\t\"version\": \"1.0.5\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/a5/11/35/a51135e3-c400-1129-0483-bd9a7cb3d54d/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/55/90/2a/55902aa9-7695-1499-7693-255f6e5343ff/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/55/90/2a/55902aa9-7695-1499-7693-255f6e5343ff/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/55/90/2a/55902aa9-7695-1499-7693-255f6e5343ff/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/naoki-ainoya/id1190031058?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1489576942,\n\t\t\t\"trackName\": \"Siro\",\n\t\t\t\"releaseDate\": \"2019-12-01T08:00:00Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6007\",\n\t\t\t\t\"6012\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.14\",\n\t\t\t\"primaryGenreName\": \"Productivity\",\n\t\t\t\"currentVersionReleaseDate\": \"2019-12-03T20:43:22Z\",\n\t\t\t\"releaseNotes\": \"We added Japanese description to AppStore.\",\n\t\t\t\"primaryGenreId\": 6007,\n\t\t\t\"sellerName\": \"Naoki AINOYA\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Siro\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"5220947\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/siro/id1489576942?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"## Configuration\\n\\nOn a settings window, please set channel name you'd like to post and your slack legacy token (slack bot token is also available, but message author is marked at bot apps name.) After that, press the save button, and then press message test button to test posting a message to slack\\n\\n## Usage\\n\\n- ctrl+shift+M: open a text window\\n- write something as you like\\n- command+enter: send the text to slack\\n- Esc: close text window\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Productivity\",\n\t\t\t\t\"Lifestyle\"\n\t\t\t],\n\t\t\t\"artistId\": 1190031058,\n\t\t\t\"artistName\": \"Naoki AINOYA\",\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"io.ainoya.macos.siro\",\n\t\t\t\"version\": \"0.3\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"supportedDevices\": [\n\t\t\t\t\"iPadMini4Cellular-iPadMini4Cellular\",\n\t\t\t\t\"iPadPro-iPadPro\",\n\t\t\t\t\"iPhone11ProMax-iPhone11ProMax\",\n\t\t\t\t\"iPadSeventhGenCellular-iPadSeventhGenCellular\",\n\t\t\t\t\"iPhone5s-iPhone5s\",\n\t\t\t\t\"iPadSeventhGen-iPadSeventhGen\",\n\t\t\t\t\"MacDesktop-MacDesktop\",\n\t\t\t\t\"iPad611-iPad611\",\n\t\t\t\t\"iPadAir2Cellular-iPadAir2Cellular\",\n\t\t\t\t\"iPadMini4-iPadMini4\",\n\t\t\t\t\"iPadPro97-iPadPro97\",\n\t\t\t\t\"iPad74-iPad74\",\n\t\t\t\t\"iPadProFourthGenCellular-iPadProFourthGenCellular\",\n\t\t\t\t\"iPadAir-iPadAir\",\n\t\t\t\t\"iPad878-iPad878\",\n\t\t\t\t\"iPadAirCellular-iPadAirCellular\",\n\t\t\t\t\"iPodTouchSeventhGen-iPodTouchSeventhGen\",\n\t\t\t\t\"iPhone11Pro-iPhone11Pro\",\n\t\t\t\t\"iPadMini5-iPadMini5\",\n\t\t\t\t\"iPadMini3Cellular-iPadMini3Cellular\",\n\t\t\t\t\"iPhone6-iPhone6\",\n\t\t\t\t\"iPadMini3-iPadMini3\",\n\t\t\t\t\"iPad71-iPad71\",\n\t\t\t\t\"iPadProSecondGen-iPadProSecondGen\",\n\t\t\t\t\"iPadProSecondGenCellular-iPadProSecondGenCellular\",\n\t\t\t\t\"iPadAir2-iPadAir2\",\n\t\t\t\t\"iPhoneXR-iPhoneXR\",\n\t\t\t\t\"iPhoneSE-iPhoneSE\",\n\t\t\t\t\"iPadPro97Cellular-iPadPro97Cellular\",\n\t\t\t\t\"iPad856-iPad856\",\n\t\t\t\t\"iPadAir3-iPadAir3\",\n\t\t\t\t\"iPad834-iPad834\",\n\t\t\t\t\"iPad76-iPad76\",\n\t\t\t\t\"iPhone8Plus-iPhone8Plus\",\n\t\t\t\t\"iPadMiniRetinaCellular-iPadMiniRetinaCellular\",\n\t\t\t\t\"iPhone11-iPhone11\",\n\t\t\t\t\"iPadMiniRetina-iPadMiniRetina\",\n\t\t\t\t\"iPad75-iPad75\",\n\t\t\t\t\"iPadProCellular-iPadProCellular\",\n\t\t\t\t\"iPhone8-iPhone8\",\n\t\t\t\t\"iPhoneX-iPhoneX\",\n\t\t\t\t\"iPad812-iPad812\",\n\t\t\t\t\"iPhone7-iPhone7\",\n\t\t\t\t\"iPhone6sPlus-iPhone6sPlus\",\n\t\t\t\t\"iPhoneSESecondGen-iPhoneSESecondGen\",\n\t\t\t\t\"iPadAir3Cellular-iPadAir3Cellular\",\n\t\t\t\t\"iPhone6s-iPhone6s\",\n\t\t\t\t\"iPhone6Plus-iPhone6Plus\",\n\t\t\t\t\"iPad72-iPad72\",\n\t\t\t\t\"iPhoneXS-iPhoneXS\",\n\t\t\t\t\"iPhoneXSMax-iPhoneXSMax\",\n\t\t\t\t\"iPodTouchSixthGen-iPodTouchSixthGen\",\n\t\t\t\t\"iPad73-iPad73\",\n\t\t\t\t\"iPadMini5Cellular-iPadMini5Cellular\",\n\t\t\t\t\"iPad612-iPad612\",\n\t\t\t\t\"iPhone7Plus-iPhone7Plus\",\n\t\t\t\t\"iPadProFourthGen-iPadProFourthGen\"\n\t\t\t],\n\t\t\t\"advisories\": [],\n\t\t\t\"isGameCenterEnabled\": false,\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/PurpleSource114/v4/6c/19/e0/6c19e0ad-b983-24f9-c4e6-fb937e4b55f4/3074bff5-66df-4e13-86c3-71d626a03317_1.png/392x696bb.png\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/PurpleSource114/v4/1e/99/c2/1e99c2a5-47b9-1ff5-b30f-808d057010a3/48f4f008-635a-444a-ab0e-dbfeec6ac190_2.png/392x696bb.png\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/PurpleSource124/v4/20/6c/8e/206c8e5f-360b-0d93-4210-d120ff84fbd4/b083af8f-dd42-469e-b5cd-1b60ef7dbaf6_3.png/392x696bb.png\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/PurpleSource124/v4/fb/69/0b/fb690b4d-b552-a176-065c-d04cf6fbbdb1/d74695d0-30cd-4328-b978-25f40f6d53ff_4.png/392x696bb.png\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/PurpleSource124/v4/b0/cf/7f/b0cf7fa9-5c46-f4cd-34d9-6031d6f9138b/8acf8a3f-757f-48b8-83f1-eb4b4e18f87a_5.png/392x696bb.png\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/PurpleSource114/v4/ba/0e/2c/ba0e2c5d-b498-e1e0-d6d7-d81997358097/85e28b81-8df2-4afe-905e-9eef2010da11_6.png/392x696bb.png\"\n\t\t\t],\n\t\t\t\"ipadScreenshotUrls\": [\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/PurpleSource114/v4/4e/71/b0/4e71b01d-b604-d77f-4d34-b1492c1df8c6/29e0061d-73b3-4e7c-b457-b974faf03061_1.png/552x414bb.png\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/PurpleSource114/v4/90/f7/4b/90f74bc2-ceb5-8f8b-aaa3-07c344336209/c14ea6a7-fdc9-437a-9210-218e01b46584_2.png/552x414bb.png\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/PurpleSource114/v4/c7/a0/e6/c7a0e66e-25b0-821f-5163-eeb677ed1bfd/40b3fc01-7cd9-4a39-9477-2f149c5344af_3.png/552x414bb.png\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/PurpleSource114/v4/4c/1f/32/4c1f32e4-e12e-b630-5235-fed7cca6c81c/2561c659-ef81-4f78-a422-b387658fbe2a_4.png/552x414bb.png\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/PurpleSource124/v4/3d/bf/b0/3dbfb05d-904f-8476-d18f-d8c5a3e1ec83/037bb39d-3998-4db5-895f-4094ff686c4e_5.png/552x414bb.png\"\n\t\t\t],\n\t\t\t\"appletvScreenshotUrls\": [],\n\t\t\t\"artworkUrl60\": \"https://is2-ssl.mzstatic.com/image/thumb/Purple114/v4/c9/02/cd/c902cd7c-9102-1dec-2eb6-ec1fb88df078/source/60x60bb.jpg\",\n\t\t\t\"artworkUrl512\": \"https://is2-ssl.mzstatic.com/image/thumb/Purple114/v4/c9/02/cd/c902cd7c-9102-1dec-2eb6-ec1fb88df078/source/512x512bb.jpg\",\n\t\t\t\"artworkUrl100\": \"https://is2-ssl.mzstatic.com/image/thumb/Purple114/v4/c9/02/cd/c902cd7c-9102-1dec-2eb6-ec1fb88df078/source/100x100bb.jpg\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/enric-enrich/id857031188?uo=4\",\n\t\t\t\"features\": [\n\t\t\t\t\"iosUniversal\"\n\t\t\t],\n\t\t\t\"kind\": \"software\",\n\t\t\t\"trackId\": 1473469253,\n\t\t\t\"trackName\": \"Veern\",\n\t\t\t\"releaseDate\": \"2019-12-18T08:00:00Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6002\",\n\t\t\t\t\"6000\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"$4.99\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"13.0\",\n\t\t\t\"primaryGenreName\": \"Utilities\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-07-27T17:28:53Z\",\n\t\t\t\"releaseNotes\": \"- You can now mark places as “favorite” to quickly find them in the “Favorites” screen.\\n- Veern now also shows you the groups of the Twist teams that you added.\",\n\t\t\t\"primaryGenreId\": 6002,\n\t\t\t\"sellerName\": \"Enric Enrich\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"Veern\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\",\n\t\t\t\t\"ES\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"14846976\",\n\t\t\t\"sellerUrl\": \"https://veern.com\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 5,\n\t\t\t\"userRatingCountForCurrentVersion\": 1,\n\t\t\t\"averageUserRating\": 5,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/veern/id1473469253?uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Veern helps you connect with people around the world.\\n\\nVeern is divided in two main sections, “Places” and “Teams”:\\n\\nIn “Places” you can add as many cities as you want to be aware of their current time. If you are logged in to iCloud, all the cities that you add will be synced across your Apple devices.\\n\\nIn “Teams” you can add up to 10 teams from Twist and Slack. Veern will then fetch your teammates and show you their current time so you can easily schedule meetings or know if it’s the right time to ask them to jump into a video call.\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Utilities\",\n\t\t\t\t\"Business\"\n\t\t\t],\n\t\t\t\"artistId\": 857031188,\n\t\t\t\"artistName\": \"Enric Enrich\",\n\t\t\t\"price\": 4.99,\n\t\t\t\"bundleId\": \"com.veern.Veern\",\n\t\t\t\"version\": \"2020.4\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 1\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple117/v4/16/0c/d4/160cd4c0-ddde-9f57-b83c-63d8ae3ac6c0/pr_source.jpg/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is2-ssl.mzstatic.com/image/thumb/Purple114/v4/bf/b5/4c/bfb54c56-3299-1ce3-70f4-bb52ea9f917c/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is2-ssl.mzstatic.com/image/thumb/Purple114/v4/bf/b5/4c/bfb54c56-3299-1ce3-70f4-bb52ea9f917c/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is2-ssl.mzstatic.com/image/thumb/Purple114/v4/bf/b5/4c/bfb54c56-3299-1ce3-70f4-bb52ea9f917c/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/lei-liu/id1135200513?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"trackId\": 1230762386,\n\t\t\t\"trackName\": \"DaysPast\",\n\t\t\t\"releaseDate\": \"2017-04-28T04:01:03Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6002\",\n\t\t\t\t\"6007\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"$0.99\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"minimumOsVersion\": \"10.10\",\n\t\t\t\"primaryGenreName\": \"Utilities\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-02-18T02:42:06Z\",\n\t\t\t\"releaseNotes\": \"Update copyright info.\",\n\t\t\t\"primaryGenreId\": 6002,\n\t\t\t\"sellerName\": \"Lei Liu\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"trackCensoredName\": \"DaysPast\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\",\n\t\t\t\t\"ZH\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"1035846\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/dayspast/id1230762386?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"A utility application to show how days pass in year/month.\\n\\nApp Features: \\n- Several styles to choose, also support customized one.\\n- Many ways to notify, including date change, Macs wakes up, etc. \\n\\nWe would love your feedback and comments. Let us know how did you like DaysPast and what changes you want to see in the upcoming updates. We would appreciate it very much.\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Utilities\",\n\t\t\t\t\"Productivity\"\n\t\t\t],\n\t\t\t\"artistId\": 1135200513,\n\t\t\t\"artistName\": \"Lei Liu\",\n\t\t\t\"price\": 0.99,\n\t\t\t\"bundleId\": \"com.100hps.dayspast.mas\",\n\t\t\t\"version\": \"1.0.6\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "Tests/MASTests/Resources/things-lookup.json",
    "content": "{\n\t\"screenshotUrls\": [\n\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple123/v4/36/fe/ff/36feffbc-a07b-e61e-f0e5-88dcc4455871/pr_source.png/800x500bb.jpg\",\n\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple113/v4/c6/85/09/c68509b2-c2c8-3000-bf85-4ead056b26f3/pr_source.png/800x500bb.jpg\",\n\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/18/42/aa/1842aab5-0500-b08b-b9a5-fc364f83fbdb/pr_source.png/800x500bb.jpg\",\n\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/de/b9/99/deb99962-f1d0-a7ad-0fc8-ef4bf906515b/pr_source.png/800x500bb.jpg\",\n\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple123/v4/41/70/7d/41707d88-8ba1-5a28-1f2f-0f2e43a73706/pr_source.png/800x500bb.jpg\",\n\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple124/v4/be/a3/a2/bea3a233-d82f-34bf-b0cd-38f262b04939/pr_source.png/800x500bb.jpg\",\n\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple113/v4/e5/41/b4/e541b49d-06ed-9ec6-1544-3df88c8dc340/pr_source.png/800x500bb.jpg\",\n\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple124/v4/8f/08/49/8f0849f4-7d20-567f-47e6-ef1bfb901619/pr_source.png/800x500bb.jpg\",\n\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple123/v4/7d/74/8a/7d748af9-50fa-e009-39a8-b5eb7774b2be/pr_source.png/800x500bb.jpg\"\n\t],\n\t\"artworkUrl60\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple124/v4/d4/b9/74/d4b974d7-0c4c-1515-49ec-ecedec84c5a0/source/60x60bb.png\",\n\t\"artworkUrl512\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple124/v4/d4/b9/74/d4b974d7-0c4c-1515-49ec-ecedec84c5a0/source/512x512bb.png\",\n\t\"artworkUrl100\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple124/v4/d4/b9/74/d4b974d7-0c4c-1515-49ec-ecedec84c5a0/source/100x100bb.png\",\n\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/tinybop-inc/id682046582?mt=12&uo=4\",\n\t\"kind\": \"mac-software\",\n\t\"minimumOsVersion\": \"10.15.0\",\n\t\"trackName\": \"Things That Go Bump\",\n\t\"trackId\": 1472954003,\n\t\"sellerName\": \"Tinybop Inc.\",\n\t\"price\": 0.99,\n\t\"fileSizeBytes\": \"12345678\",\n\t\"formattedPrice\": \"$0.99\",\n\t\"releaseNotes\": \"* BOOM *, this is a BIG update. The house spawns a game room, complete with video games you can ENTER INTO. It's fun and a little bit weird! Try it! \\n»-(¯`·.·´¯)->\",\n\t\"primaryGenreId\": 6014,\n\t\"primaryGenreName\": \"Games\",\n\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\"releaseDate\": \"2019-10-18T07:00:00Z\",\n\t\"genreIds\": [\n\t\t\"6014\",\n\t\t\"7001\",\n\t\t\"7009\"\n\t],\n\t\"currentVersionReleaseDate\": \"2020-03-18T17:39:23Z\",\n\t\"trackCensoredName\": \"Things That Go Bump\",\n\t\"languageCodesISO2A\": [\n\t\t\"EN\"\n\t],\n\t\"sellerUrl\": \"https://tinybop.com\",\n\t\"contentAdvisoryRating\": \"4+\",\n\t\"averageUserRatingForCurrentVersion\": 0,\n\t\"userRatingCountForCurrentVersion\": 0,\n\t\"averageUserRating\": 0,\n\t\"trackViewUrl\": \"https://apps.apple.com/us/app/things-that-go-bump/id1472954003?mt=12&uo=4\",\n\t\"trackContentRating\": \"4+\",\n\t\"description\": \"Have you ever heard something go bump in the night? \\nPerhaps you’ve caught wind of a spirit or sprite. \\nWhen the house is asleep,\\nand there’s dark all around, \\nspirits from objects awake and abound. \\n\\nThe spirits are crafty and like to cause trouble. \\nThey're called yōkai and together, they double. \\nMixing and mashing, they join to fight. \\nCan you help them conquer this mysterious night? \\n\\nPlay with one person, two, three or four. \\nFirst you’ll need to escape the dark junk drawer. \\n\\n. . . . . . . . . . . . . . . . . . . .\\nIn Things That go Bump, familiar objects and rooms come to life every night, and nothing looks quite as does in the day. Create your creature, and battle your friends, but beware the house spirits! They can destroy and they can give life. Battle, create, and make your way through the rooms of the house, and slowly you will unravel the secret of Things that Go Bump.  \\n\\nFeatures:\\n    * Spirits wake up objects and create yōkai (spirit creatures)\\n    * Combine everyday objects like umbrellas, staplers, cheese graters and more to create everchanging characters \\n    * Connect to other players via Game Center and face-off against other spirit creatures and house spirits\\n    * Add or swap objects to give your spirit creature new skills\\n    * Gain energy by making mischief, defeating other yōkai, and conquering the house spirits\\n    * Advance through the house (new rooms will be added throughout the year)\\n    * Test your curiosity and creativity with new challenges in every room\\n    * Play with 1-4 players across iPads, iPhones, iPods, AppleTVs and Macs\\n    * Fun and challenging for the whole family\\n    * Intuitive, safe, hilarious kid-friendly design\\n    * New levels introduced roughly every 2 months\\n    * Original artwork by Adrian Fernandez\\n    * Original sound design\\n\\nTinybop, Inc. is a Brooklyn-based studio of designers, engineers, and artists. We make toys for tomorrow. We’re all over the internet.\\n\\n     Visit us: www.tinybop.com\\n     Follow us: twitter.com/tinybop\\n     Like us: facebook.com/tinybop\\n     Peek behind the scenes: instagram.com/tinybop\\n\\nWe love hearing your stories! If you have ideas, or something isn’t working as you expect it to, please contact us: support@tinybop.com.\\n\\nPsst! It's not Tiny Bop, or Tiny Bob, or Tiny Pop. It's Tinybop. :)\",\n\t\"currency\": \"USD\",\n\t\"artistId\": 682046582,\n\t\"artistName\": \"Tinybop Inc.\",\n\t\"genres\": [\n\t\t\"Games\",\n\t\t\"Action\",\n\t\t\"Family\"\n\t],\n\t\"bundleId\": \"uikitformac.com.tinybop.thingamabops\",\n\t\"version\": \"1.3.0\",\n\t\"wrapperType\": \"software\",\n\t\"userRatingCount\": 0\n}\n"
  },
  {
    "path": "Tests/MASTests/Resources/things.json",
    "content": "{\n\t\"resultCount\": 12,\n\t\"results\": [\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/6f/4c/e5/6f4ce5d6-7caa-d1eb-bbc9-86558e97d2ba/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple113/v4/92/b4/f8/92b4f8f5-f133-abd8-db17-135ac27bb1fa/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/72/63/63/726363b9-45ff-f93e-975c-fb69836eaf1a/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/29/fa/63/29fa63e3-3cb2-8b8a-8541-31fa9b7ef27f/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/da/17/5f/da175f95-c2cd-e5df-8cbc-d800d6770c64/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple113/v4/f1/82/37/f182376c-4f25-6dbb-c6a8-5e6c1c617620/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple114/v4/69/3b/12/693b12e6-67d5-8252-7607-3438e420bbaa/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple114/v4/69/3b/12/693b12e6-67d5-8252-7607-3438e420bbaa/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple114/v4/69/3b/12/693b12e6-67d5-8252-7607-3438e420bbaa/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/cultured-code-gmbh-co-kg/id284971784?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"minimumOsVersion\": \"10.13.0\",\n\t\t\t\"trackName\": \"Things 3\",\n\t\t\t\"trackId\": 904280696,\n\t\t\t\"sellerName\": \"Cultured Code GmbH & Co. KG\",\n\t\t\t\"releaseNotes\": \"• Moved the database file to a new location (now at /Library/Group Containers/).\\n• Increased the clickable area of items in the sidebar.\\n• Improved the formatting of years in Japanese.\\n• Fixed some crashes that could occur when hitting Cmd+[ or ] in Quick Entry while the When popover was visible.\\n• Updated the crash reporter.\\n• Some sync improvements.\\n\\n\\nNEW IN 3.12\\n\\nWe’re excited to release Things 3.12 – a big update for our Watch app!\\n\\nWe’ve entirely rebuilt its foundation to allow it to sync and operate without your phone being nearby. We’ve also taken this opportunity to add some often-requested features to the app. For more information about this release, please visit our blog: thingsapp.com\\n\\nThere are no huge changes in this release for Mac, but there’s one great new feature you should know about: you can now edit the Tags or Deadlines of collapsed to-dos – even for multiple to-dos at once – by hitting Cmd+Shift+T or D. It’s super convenient :)\",\n\t\t\t\"primaryGenreId\": 6007,\n\t\t\t\"primaryGenreName\": \"Productivity\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"releaseDate\": \"2017-05-18T16:42:04Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6007\",\n\t\t\t\t\"6000\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"$49.99\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-08-04T07:57:44Z\",\n\t\t\t\"trackCensoredName\": \"Things 3\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\",\n\t\t\t\t\"FR\",\n\t\t\t\t\"DE\",\n\t\t\t\t\"IT\",\n\t\t\t\t\"JA\",\n\t\t\t\t\"RU\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"ES\",\n\t\t\t\t\"ZH\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"17474797\",\n\t\t\t\"sellerUrl\": \"https://culturedcode.com/things/\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/things-3/id904280696?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Get things done! The award-winning Things app helps you plan your day, manage your projects, and make real progress toward your goals.\\n\\nBest of all, it’s easy to use. Within the hour, you’ll have everything off your mind and neatly organized—from routine tasks to your biggest life goals—and you can start focusing on what matters today.\\n\\n“Things offers the best combination of design and functionality of any app we tested, with nearly all the features of other power user applications and a delightful interface that never gets in the way of your work.”\\n—Wirecutter, The New York Times\\n\\n\\nKEY FEATURES\\n\\n• Your To-Dos\\nYour basic building block is the almighty To-Do—each a small step toward a great accomplishment. You can add notes, tag it, schedule it, and break it down into smaller steps.\\n\\n• Your Projects\\nCreate a Project for any big goal, then add the to-dos to reach it. Use headings to structure your list as you outline your plan. There’s also a place to jot down your notes, and a deadline to keep you on schedule.\\n\\n• Your Areas\\nCreate an Area for each sphere of your life, such as Work, Family, Finance, and so on. This keeps everything neatly organized, and helps you see the big picture as you set your plans in motion.\\n\\n• Your Plan\\nEverything on your schedule is neatly laid out in the Today and Upcoming lists, which show your to-dos and calendar events. Each morning, see what you planned for Today and decide what you want to do. The rest is down to you :)\\n\\n\\nMORE THINGS TO LOVE\\n\\nAs you dive deeper, you’ll find Things packed with helpful features. Here are just a few:\\n\\n• Reminders — set a time and Things will remind you.\\n• Repeaters — automatically repeat to-dos on a schedule you set.\\n• This Evening — a special place for your evening plans.\\n• Calendar integration — see your events and to-dos together.\\n• Tags — categorize your to-dos and quickly filter lists.\\n• Quick Entry — create to-dos from anywhere, as soon as the thought hits you.\\n• Quick Find — instantly locate to-dos, headings, or tags.\\n• Type Travel — jump from list to list with your keyboard; just start typing!\\n• Mail to Things — forward an email to Things; now it’s a to-do.\\n• And much more!\\n\\n\\nMADE FOR MAC\\n\\nThings is tailored to the Mac with deep system integrations as well. A great example is Quick Entry with Autofill: a shortcut that grabs content from other apps and adds it to Things for you, such as a link to a website or an email you want to get back to.\\n\\nYou can also enjoy a beautiful dark mode at sunset, connect your calendars, enable a Things widget, use your Mac’s Touch Bar, import from Reminders—Things can do it all! There’s even AppleScript support if you need powerful automation.\\n\\n\\nSTAY PRODUCTIVE ON THE GO\\n\\nThings has full-featured apps for iPhone, iPad, and Apple Watch as well (sold separately). All your devices sync seamlessly via our free Things Cloud service. It’s great to have everything at your fingertips when you need it!\\n\\n\\nAWARD-WINNING DESIGN\\n\\nMade in Stuttgart, with two Apple Design Awards to its name, Things is a fine example of German engineering: designed, not only to look fantastic, but to be perfectly functional as well. Every detail is thoughtfully considered, then polished to perfection.\\n\\n“It’s like the unicorn of productivity tools: deep enough for serious work, surprisingly easy to use, and gorgeous enough to enjoy staring at.”\\n—Apple\\n\\n\\nGET THINGS TODAY\\n\\nWhatever it is you want to accomplish in life, Things can help you get there. Install the app today and see what you can do!\\n\\nVisit our website now and get a free 15-day trial for your Mac: thingsapp.com\\n\\nIf you have any questions, please get in touch. We provide professional support and will be glad to help you!\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"artistId\": 284971784,\n\t\t\t\"artistName\": \"Cultured Code GmbH & Co. KG\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Productivity\",\n\t\t\t\t\"Business\"\n\t\t\t],\n\t\t\t\"price\": 49.99,\n\t\t\t\"bundleId\": \"com.culturedcode.ThingsMac\",\n\t\t\t\"version\": \"3.12.6\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple123/v4/c9/5d/af/c95daf17-c405-56f0-90f5-9411828e44d2/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/94/32/3b/94323b37-f81b-7ba8-a280-b951e7e840de/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/82/f1/35/82f1356d-1e68-8f9d-3967-566e256f9265/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple123/v4/dc/ad/83/dcad839b-7705-e4c0-180a-2f97cb68054d/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple123/v4/21/50/6a/21506a09-c48c-d25e-dfa5-c0d6aa4cdd9d/pr_source.jpg/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple114/v4/09/64/61/096461c1-f392-ec7d-13dd-2caa927d8244/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple114/v4/09/64/61/096461c1-f392-ec7d-13dd-2caa927d8244/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple114/v4/09/64/61/096461c1-f392-ec7d-13dd-2caa927d8244/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/appest-limited/id434073155?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"minimumOsVersion\": \"10.12\",\n\t\t\t\"trackName\": \"TickTick: Things & Tasks To Do\",\n\t\t\t\"trackId\": 966085870,\n\t\t\t\"sellerName\": \"Appest Limited\",\n\t\t\t\"releaseNotes\": \"- Bug fixes and improvements.\\n\\nRecent Updates:\\n- Customizable Section in List View.\\n- Tag names can be capitalized.\\n- The number of Pomos can now be estimated beforehand.\\n- Lists under different folders can share the same name.\\n- New city themes! Los Angeles and Cairo.\\n\\nThanks for using TickTick! We'll bring regular updates to give you more pleasant experience with performance and stability.\\nWe'll read all reviews in App Store and evaluate your feedbacks carefully. Any issues encountered during the use, you may write to us via Avatar -> Feedback & Suggestions -> Submit feedback, we will get back to you asap.\\nTickTick team with love.\",\n\t\t\t\"primaryGenreId\": 6007,\n\t\t\t\"primaryGenreName\": \"Productivity\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"releaseDate\": \"2016-03-04T06:37:31Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6007\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-08-27T01:27:34Z\",\n\t\t\t\"trackCensoredName\": \"TickTick: Things & Tasks To Do\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\",\n\t\t\t\t\"ZH\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"24698702\",\n\t\t\t\"sellerUrl\": \"https://ticktick.com\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/ticktick-things-tasks-to-do/id966085870?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Design exclusively for macOS, TickTick is your daily must-have to-do & task list to get all things done.\\nTickTick can be accessed on more than 10 different platforms including Mac, iPhone, iPad, Apple Watch which enables you to manage tasks on all your devices/Web.\\n\\nKey features: \\n- Add task via shortcut (Command+Shift+A)\\n- Instant reminder\\n- Set priority levels to tasks\\n- Set flexible recurring tasks \\n- Create checklists within tasks \\n- Sort tasks by order/date/name/priority \\n- Sync all your tasks across all devices \\n\\nTickTick is free but you can also upgrade to Premium account for full access of premium features for $2.99 a month or $27.99 a year through an auto-renewing subscription.\\n\\nPremium Features: \\n- Grid view and Timeline view of calendar\\n- Duration\\n- Custom Smart List\\n- Description for checklist\\n- Reminders for sub-tasks\\n- More lists and tasks (299 lists, 999 tasks in each list, 199 subtasks in each task)\\n- Add at most 5 reminders to each task\\n- Share a task list up to 19 members for better task collaboration\\n- Upload up to 99 attachments every day\\n\\nSubscriptions for Premium account will be charged to your credit card through your iTunes account. Your subscription will automatically renew unless cancelled at least 24-hours before the end of the current period. You will not be able to cancel a subscription during the active period. You can manage your subscriptions in the Account Settings after purchase. \\n\\nHow TickTick makes you productive: \\n- Get all things done \\n- Never miss a schedule\\n- Make work more productive \\n- Keep life on track \\n\\nConnect with us: \\nFacebook: https://www.facebook.com/TickTickApp\\nTwitter: https://twitter.com/TickTickTeam @TickTickTeam\\nHelp Center: https://help.ticktick.com/\\n\\nPrivacy Policy: https://www.ticktick.com/about/privacy\\nTerms of Use: https://www.ticktick.com/about/tos\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"artistId\": 434073155,\n\t\t\t\"artistName\": \"Appest Limited\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Productivity\"\n\t\t\t],\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.TickTick.task.mac\",\n\t\t\t\"version\": \"3.7.11\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple1/v4/79/5c/63/795c63aa-698c-1c6c-b6da-e7ebba718d01/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple30/v4/15/4d/40/154d4071-4a6f-dcd7-0d15-2e495f6f4710/mzm.mvtkjcyn.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple2/v4/e0/31/dc/e031dc74-ce06-afe3-fd8e-8693f6c7c50c/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple1/v4/fc/8d/23/fc8d2367-725d-11dd-6da9-816a7780a1d9/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple71/v4/ff/4d/6b/ff4d6b03-2f12-e12d-9bb3-b3607bcd8ad8/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple71/v4/ff/4d/6b/ff4d6b03-2f12-e12d-9bb3-b3607bcd8ad8/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple71/v4/ff/4d/6b/ff4d6b03-2f12-e12d-9bb3-b3607bcd8ad8/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/antlogic/id364746702?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"minimumOsVersion\": \"10.6\",\n\t\t\t\"trackName\": \"Simple Antnotes\",\n\t\t\t\"trackId\": 846599902,\n\t\t\t\"sellerName\": \"Mykola Olshevskyi\",\n\t\t\t\"releaseNotes\": \"- added option to disable gradient background\\n- added option to create new notes in bottom left/right corners\\n- changed delay for close/options buttons showing\\n- some minor compatibility and UI fixes\\n- fixed German localisation\",\n\t\t\t\"primaryGenreId\": 6007,\n\t\t\t\"primaryGenreName\": \"Productivity\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"releaseDate\": \"2014-03-28T12:49:14Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6007\",\n\t\t\t\t\"6002\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"currentVersionReleaseDate\": \"2016-09-24T17:06:52Z\",\n\t\t\t\"trackCensoredName\": \"Simple Antnotes\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\",\n\t\t\t\t\"DE\",\n\t\t\t\t\"RU\",\n\t\t\t\t\"UK\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"1002100\",\n\t\t\t\"sellerUrl\": \"https://www.antlogic.com/apps/antnotes\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/simple-antnotes/id846599902?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Antnotes are like paper notes: they are glued to your monitor, but from the other side of the screen.\\n\\nThis nice and handy application lives in the menu bar for faster access and has the following features:\\n\\n- customizable background, font and text color\\n- pin note to desktop to make it stay atop of other windows\\n- translucent notes\\n- make new notes by dragging text, images and files to the menu bar icon\\n- drag images and sounds to note contents\\n- automatically hide notes when inactive\\n- quick access via menu bar icon\\n- configurable global shortcuts to create new note or show/hide all notes\\n- integration with services: create new note from any text in any application\\n- snap to screen bounds and other notes\\n- archive with all closed notes - do not lose your information by accidentally closing a note\\n- smart position choosing for different display configurations\\n\\nWant more features? Let us know, or check out our Antnotes application!\\n\\nVisit our support forums: https://www.antlogic.com/forum/\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"artistId\": 364746702,\n\t\t\t\"artistName\": \"AntLogic\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Productivity\",\n\t\t\t\t\"Utilities\"\n\t\t\t],\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"ua.com.AntLogic.SimpleAntnotes\",\n\t\t\t\"version\": \"1.6.1\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"appletvScreenshotUrls\": [],\n\t\t\t\"supportedDevices\": [\n\t\t\t\t\"iPadMini4-iPadMini4\",\n\t\t\t\t\"iPadProSecondGen-iPadProSecondGen\",\n\t\t\t\t\"iPhone11-iPhone11\",\n\t\t\t\t\"iPad71-iPad71\",\n\t\t\t\t\"iPadMiniRetinaCellular-iPadMiniRetinaCellular\",\n\t\t\t\t\"iPhone8Plus-iPhone8Plus\",\n\t\t\t\t\"iPhone6sPlus-iPhone6sPlus\",\n\t\t\t\t\"iPadMini5-iPadMini5\",\n\t\t\t\t\"iPadProFourthGen-iPadProFourthGen\",\n\t\t\t\t\"iPhoneXS-iPhoneXS\",\n\t\t\t\t\"iPadAir3Cellular-iPadAir3Cellular\",\n\t\t\t\t\"iPadAir3-iPadAir3\",\n\t\t\t\t\"iPadMini4Cellular-iPadMini4Cellular\",\n\t\t\t\t\"iPadProCellular-iPadProCellular\",\n\t\t\t\t\"MacDesktop-MacDesktop\",\n\t\t\t\t\"iPadMini3-iPadMini3\",\n\t\t\t\t\"iPhoneXR-iPhoneXR\",\n\t\t\t\t\"iPhoneSE-iPhoneSE\",\n\t\t\t\t\"iPad611-iPad611\",\n\t\t\t\t\"iPhone7-iPhone7\",\n\t\t\t\t\"iPad73-iPad73\",\n\t\t\t\t\"iPad812-iPad812\",\n\t\t\t\t\"iPadAir2Cellular-iPadAir2Cellular\",\n\t\t\t\t\"iPhoneX-iPhoneX\",\n\t\t\t\t\"iPadMini5Cellular-iPadMini5Cellular\",\n\t\t\t\t\"iPadPro97-iPadPro97\",\n\t\t\t\t\"iPad834-iPad834\",\n\t\t\t\t\"iPadProSecondGenCellular-iPadProSecondGenCellular\",\n\t\t\t\t\"iPhone5s-iPhone5s\",\n\t\t\t\t\"iPad75-iPad75\",\n\t\t\t\t\"iPadMini3Cellular-iPadMini3Cellular\",\n\t\t\t\t\"iPad878-iPad878\",\n\t\t\t\t\"iPhone6-iPhone6\",\n\t\t\t\t\"iPadAir-iPadAir\",\n\t\t\t\t\"iPadPro97Cellular-iPadPro97Cellular\",\n\t\t\t\t\"iPadSeventhGen-iPadSeventhGen\",\n\t\t\t\t\"iPodTouchSixthGen-iPodTouchSixthGen\",\n\t\t\t\t\"iPhoneXSMax-iPhoneXSMax\",\n\t\t\t\t\"iPad612-iPad612\",\n\t\t\t\t\"iPadPro-iPadPro\",\n\t\t\t\t\"iPodTouchSeventhGen-iPodTouchSeventhGen\",\n\t\t\t\t\"iPhone11ProMax-iPhone11ProMax\",\n\t\t\t\t\"iPadMiniRetina-iPadMiniRetina\",\n\t\t\t\t\"iPad76-iPad76\",\n\t\t\t\t\"iPadProFourthGenCellular-iPadProFourthGenCellular\",\n\t\t\t\t\"iPadSeventhGenCellular-iPadSeventhGenCellular\",\n\t\t\t\t\"iPhoneSESecondGen-iPhoneSESecondGen\",\n\t\t\t\t\"iPad74-iPad74\",\n\t\t\t\t\"iPhone6s-iPhone6s\",\n\t\t\t\t\"iPhone7Plus-iPhone7Plus\",\n\t\t\t\t\"iPadAir2-iPadAir2\",\n\t\t\t\t\"iPad72-iPad72\",\n\t\t\t\t\"iPhone6Plus-iPhone6Plus\",\n\t\t\t\t\"iPadAirCellular-iPadAirCellular\",\n\t\t\t\t\"Watch4-Watch4\",\n\t\t\t\t\"iPhone8-iPhone8\",\n\t\t\t\t\"iPad856-iPad856\",\n\t\t\t\t\"iPhone11Pro-iPhone11Pro\"\n\t\t\t],\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple113/v4/2b/ce/8f/2bce8ffa-545b-050c-1dd9-2aeef532facd/pr_source.png/406x228bb.png\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/fb/36/14/fb36142e-17ba-fdab-90c6-e8f9d3c080ef/pr_source.png/406x228bb.png\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple113/v4/4e/e2/de/4ee2de74-d0ef-010b-19f6-63755aa0175c/pr_source.png/406x228bb.png\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple113/v4/46/8e/bd/468ebdd3-73a9-ec6a-b4da-6931ce887cff/pr_source.png/406x228bb.png\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/a4/9c/fa/a49cfa14-69e0-f1cf-3924-6ff878027b2d/pr_source.png/406x228bb.png\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple123/v4/c1/94/cc/c194ccb6-c15a-c0a5-47a6-3ddd625fd98d/pr_source.png/406x228bb.png\"\n\t\t\t],\n\t\t\t\"ipadScreenshotUrls\": [\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/3f/23/5e/3f235e16-c049-8ee8-ebdc-3d52f25f2636/pr_source.png/552x414bb.png\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/80/48/1d/80481dff-e404-721c-920e-4688f860cf27/pr_source.png/552x414bb.png\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple123/v4/58/a2/c9/58a2c970-1bd3-6f4d-1bdc-502f75faaa6a/pr_source.png/552x414bb.png\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple123/v4/2c/a6/06/2ca606eb-8b40-219a-34c5-626f79b7e593/pr_source.png/552x414bb.png\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/c7/d7/04/c7d70441-51bd-1417-c7bf-a5d2702380e4/pr_source.png/552x414bb.png\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/87/e0/75/87e075fd-a979-6151-5744-56ab76ac8f18/pr_source.png/552x414bb.png\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple114/v4/b3/ce/e9/b3cee939-9c28-6e05-f600-2e1b9419e0d2/source/60x60bb.jpg\",\n\t\t\t\"artworkUrl512\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple114/v4/b3/ce/e9/b3cee939-9c28-6e05-f600-2e1b9419e0d2/source/512x512bb.jpg\",\n\t\t\t\"artworkUrl100\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple114/v4/b3/ce/e9/b3cee939-9c28-6e05-f600-2e1b9419e0d2/source/100x100bb.jpg\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/volodymyr-yahenskyi/id961335645?uo=4\",\n\t\t\t\"isGameCenterEnabled\": false,\n\t\t\t\"advisories\": [],\n\t\t\t\"features\": [\n\t\t\t\t\"iosUniversal\"\n\t\t\t],\n\t\t\t\"kind\": \"software\",\n\t\t\t\"minimumOsVersion\": \"11.0\",\n\t\t\t\"trackName\": \"Random: Lists & Decision Maker\",\n\t\t\t\"trackId\": 1128190780,\n\t\t\t\"sellerName\": \"Volodymyr Yahenskyi\",\n\t\t\t\"releaseNotes\": \"• Fixed crash when adding items to a new list\\n• Fixed lists sync on Apple Watch\\n\\nThanks for using the Random!\\nThis release also contains bug fixes and performance improvements.\",\n\t\t\t\"primaryGenreId\": 6012,\n\t\t\t\"primaryGenreName\": \"Lifestyle\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"releaseDate\": \"2016-07-05T22:00:04Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6012\",\n\t\t\t\t\"7009\",\n\t\t\t\t\"6014\",\n\t\t\t\t\"7004\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-08-29T19:21:51Z\",\n\t\t\t\"trackCensoredName\": \"Random: Lists & Decision Maker\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\",\n\t\t\t\t\"RU\",\n\t\t\t\t\"UK\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"76392448\",\n\t\t\t\"sellerUrl\": \"https://yahenskyi.dev/random/\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 4.6104900000000004212097337585873901844024658203125,\n\t\t\t\"userRatingCountForCurrentVersion\": 1525,\n\t\t\t\"averageUserRating\": 4.6104900000000004212097337585873901844024658203125,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/random-lists-decision-maker/id1128190780?uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Need a random number? Or can’t you decide what to do? Random is a powerful app that will solve all such problems.\\n\\nFeatures:\\n• Number generator (from a range 0 - 999999999)\\n• Letter generator\\n• Dice roller (roll up to 4 regular dices in one go)\\n• A custom item from a list generator\\n• Yes or No \\n• Coin flipper\\n• Card generator\\n• Rock-Paper-Scissors\\n• Map Point\\n\\nGenerate a new random number simply by tapping a ​randomize button or by touching the Apple Watch screen. For those who want a bit of additional exercise, shaking your iOS device will also result in a new random response.\\n\\nUse Force Touch for setting the minimum or maximum values in your Apple Watch app. Same for the number of dices​, cards, and selection of lists.\\n\\nRandom Premium subscription benefits:\\n• Sync: Get access to your data from all your devices.\\n• Themes: Customize the app with various themes and background images.\\n• No advertising.\\n\\nIf you decide to get Random Premium subscription, your purchase will be charged to your iTunes account. 1 month costs $2.99 and 1 year costs $11.99. Active subscriptions will be auto-renewed 24 hours before the expiry date. You can manage subscriptions from Account in iTunes after subscribing, you’ll also be able to cancel the auto-renewing subscription from there at any time. Any unused portion of the free trial period will be forfeited if you purchase a subscription to Random Premium before your trial expires.\\n\\nTerms & Conditions: https://yahenskyi.dev/terms-conditions/\\nPrivacy Policy: https://yahenskyi.dev/privacy-policy/\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"artistId\": 961335645,\n\t\t\t\"artistName\": \"Volodymyr Yahenskyi\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Lifestyle\",\n\t\t\t\t\"Family\",\n\t\t\t\t\"Games\",\n\t\t\t\t\"Board\"\n\t\t\t],\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.yahenskyi.random\",\n\t\t\t\"version\": \"2.2.10\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 1525\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple71/v4/0e/74/bb/0e74bb9a-5ac2-5d5f-516a-5f1c12e95328/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple71/v4/36/54/f0/3654f064-4013-95e6-2683-c89ab8e51102/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple71/v4/1a/75/86/1a758637-9db5-007c-595b-b724e9083321/pr_source.jpg/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple114/v4/b0/7b/ed/b07bed5e-d977-6655-7a6a-d35a90901fba/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple114/v4/b0/7b/ed/b07bed5e-d977-6655-7a6a-d35a90901fba/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple114/v4/b0/7b/ed/b07bed5e-d977-6655-7a6a-d35a90901fba/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/any-case-solutions/id1396419026?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"minimumOsVersion\": \"10.10\",\n\t\t\t\"trackName\": \"Task Planner - To Do List\",\n\t\t\t\"trackId\": 1063681909,\n\t\t\t\"sellerName\": \"Any Case Solutions, OOO\",\n\t\t\t\"releaseNotes\": \"We’ve updated the app! In the new version:\\n- less bugs;\\n- minor changes in the interface;\\n- some general improvements.\\nYour opinion is important to us! Please, leave your feedback - we will gladly consider all your wishes and suggestions.\",\n\t\t\t\"primaryGenreId\": 6000,\n\t\t\t\"primaryGenreName\": \"Business\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"releaseDate\": \"2016-01-07T00:04:36Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6000\",\n\t\t\t\t\"6007\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-07-17T23:48:12Z\",\n\t\t\t\"trackCensoredName\": \"Task Planner - To Do List\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\",\n\t\t\t\t\"FR\",\n\t\t\t\t\"DE\",\n\t\t\t\t\"IT\",\n\t\t\t\t\"JA\",\n\t\t\t\t\"KO\",\n\t\t\t\t\"PT\",\n\t\t\t\t\"RU\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"ES\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"27930644\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/task-planner-to-do-list/id1063681909?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Plan Your Tasks is a productivity tool that allows you to capture your ideas and duties in one place. \\nManage everything you have to do while working with many different tasks!\\n\\nEasy task management - create, organize, and prioritize tasks;\\n- Set notifications;\\n- Add comments;\\n- Sort tasks by categories;\\n- Track due dates.\\n\\nNew approach to agenda\\n- Build-in calendar;\\n- Coherent tutorial mode;\\n- Magic Trackpad 2 support.\\n\\nCapture all your flash ideas and duties in the calendar and manage your to dos while working with many tasks more effectively.\\n\\n\\nPrivacy Policy: https://anycasesolutions.com/privacy\\nTerms Of Use: https://anycasesolutions.com/tos\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"artistId\": 1396419026,\n\t\t\t\"artistName\": \"Any Case Solutions\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Business\",\n\t\t\t\t\"Productivity\"\n\t\t\t],\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.newtechnologies.iPlanTasksinapp\",\n\t\t\t\"version\": \"2.1.2\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple3/v4/69/a0/58/69a0583d-02fd-1d37-cb33-19b80578e9e5/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple3/v4/09/be/29/09be2981-4d08-a021-423a-29cc212c1b59/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple7/v4/28/5a/f4/285af4d8-37e6-118a-ff28-a4211eeb1122/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple3/v4/50/4d/52/504d520c-4f8c-b011-d1e0-18addb5700a8/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple3/v4/f2/6e/07/f26e0760-efb1-0353-3ebd-9fd2803f4b3d/pr_source.jpg/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple69/v4/ac/6e/9a/ac6e9aea-8f4b-66bd-6046-c1735f27806f/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple69/v4/ac/6e/9a/ac6e9aea-8f4b-66bd-6046-c1735f27806f/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is5-ssl.mzstatic.com/image/thumb/Purple69/v4/ac/6e/9a/ac6e9aea-8f4b-66bd-6046-c1735f27806f/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/realmac-software/id310591643?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"minimumOsVersion\": \"10.10\",\n\t\t\t\"trackName\": \"Clear – Tasks, Reminders & To-Do Lists\",\n\t\t\t\"trackId\": 504544917,\n\t\t\t\"sellerName\": \"Realmac Software Limited\",\n\t\t\t\"releaseNotes\": \"Thanks for using Clear! Just two small enhancements in today’s update:\\n\\n- We’ve tweaked (increased) the delay before “Click to Clear” appears.\\n- We’ve ensured compatibility with OS X El Capitan.\\n\\nStay productive, and follow @realmacsoftware on Twitter for the latest news!\",\n\t\t\t\"primaryGenreId\": 6007,\n\t\t\t\"primaryGenreName\": \"Productivity\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"releaseDate\": \"2012-11-08T08:00:00Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6007\",\n\t\t\t\t\"6012\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"$9.99\",\n\t\t\t\"currentVersionReleaseDate\": \"2015-08-19T14:05:32Z\",\n\t\t\t\"trackCensoredName\": \"Clear – Tasks, Reminders & To-Do Lists\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"13109875\",\n\t\t\t\"sellerUrl\": \"https://impending.com\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/clear-tasks-reminders-to-do-lists/id504544917?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Over 2.5 million people de-clutter their lives with Clear, so stop stalling and start organizing your daily routine.\\n\\nClear is the revolutionary to-do and reminders app that makes you more productive. Just start typing to add to-dos, and once you start organizing your life with Clear you’ll wonder how you ever managed without it.\\n\\n- Simple gestural design that allows you to focus on your to-dos. Designed for the Magic Trackpad, but works great with a mouse too!\\n- Full keyboard navigation. Just start typing to create to-dos.\\n- Use separate lists to organize every aspect of your life.\\n-  iCloud sync built-in so you can be productive everywhere.\\n- Set reminders so you’ll never forget important tasks.\\n- Personalize your Clear lists with themes and make them your own.\\n- Syncs with Clear for iOS (available separately on the App Store).\\n\\nClear is built by a small team, dedicated to bringing you frequent free feature updates. We’d love to know how we can make you even more productive, so get in touch via the App Store “Support” link, or tweet us @UseClear.\\n\\nClear for Mac and Clear for iOS are not affiliated with or endorsed by CLEAR Wireless.\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"artistId\": 310591643,\n\t\t\t\"artistName\": \"Realmac Software\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Productivity\",\n\t\t\t\t\"Lifestyle\"\n\t\t\t],\n\t\t\t\"price\": 9.99,\n\t\t\t\"bundleId\": \"com.realmacsoftware.clear.mac\",\n\t\t\t\"version\": \"1.1.7\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple113/v4/cd/bd/44/cdbd44af-06eb-21d6-a793-43dae1077c47/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/e9/8f/17/e98f17c6-787b-b180-6f8d-fb8385ceedd3/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/43/12/a2/4312a25b-f773-9c1a-ddd4-2515d948cc27/pr_source.jpg/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/97/0d/b4/970db444-bbd9-ed77-439e-001bce006e17/pr_source.jpg/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple113/v4/6b/f0/58/6bf058c1-90ab-5bdf-7c06-18de305efd6d/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple113/v4/6b/f0/58/6bf058c1-90ab-5bdf-7c06-18de305efd6d/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is1-ssl.mzstatic.com/image/thumb/Purple113/v4/6b/f0/58/6bf058c1-90ab-5bdf-7c06-18de305efd6d/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/shenzhen-tomato-software-technology-co-ltd/id966057212?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"minimumOsVersion\": \"10.12\",\n\t\t\t\"trackName\": \"Focus To-Do: Pomodoro & Tasks\",\n\t\t\t\"trackId\": 1258530160,\n\t\t\t\"sellerName\": \"Shenzhen Tomato Software Technology Co., Ltd.\",\n\t\t\t\"releaseNotes\": \"1.Support new languages\\n2.Bug fix\",\n\t\t\t\"primaryGenreId\": 6007,\n\t\t\t\"primaryGenreName\": \"Productivity\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"releaseDate\": \"2017-08-02T03:45:26Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6007\",\n\t\t\t\t\"6002\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-05-03T04:38:29Z\",\n\t\t\t\"trackCensoredName\": \"Focus To-Do: Pomodoro & Tasks\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"CS\",\n\t\t\t\t\"EN\",\n\t\t\t\t\"FR\",\n\t\t\t\t\"DE\",\n\t\t\t\t\"ID\",\n\t\t\t\t\"IT\",\n\t\t\t\t\"JA\",\n\t\t\t\t\"KO\",\n\t\t\t\t\"PL\",\n\t\t\t\t\"PT\",\n\t\t\t\t\"RO\",\n\t\t\t\t\"RU\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"ES\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"TR\",\n\t\t\t\t\"VI\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"12135791\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/focus-to-do-pomodoro-tasks/id1258530160?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Focus To-Do combines Pomodoro Timer with Task Management, it is a science-based app that will motivate you to stay focused and get things done. \\n\\nIt brings Pomodoro Technique and To Do List into one place, you can capture and organize tasks into your todo lists, start focus timer and focus on work & study, set reminders for important tasks and errands, check the time spent at work. \\n\\nIt's the ultimate app for managing Tasks, Reminders, Lists, Calendar events, Grocery lists, checklist, helping you focus on work & study and tracking your working hours.\\n\\nFocus To-Do syncs between your phone and computer, so you can access your lists from anywhere.\\n\\nHow it works:\\n       1. Pick a task you need to accomplish.\\n       2. Set a timer for 25 minutes, keep focused and start working.\\n       3. When the pomodoro timer rings, take a 5 minute break.\\n \\nKey Features:\\n\\n-  Pomodoro Timer：Stay focused and get more things done.\\n       Pause and resume Pomodoro\\n       Customizable pomodoro/breaks lengths\\n       Notification before the end of a Pomodoro\\n       Support for short and long breaks\\n       Skip a break after the end of a Pomodoro\\n       Continuous Mode\\n       \\n-  Tasks Management: Task Organizer, Schedule Planner, Reminder, Habit Tracker, Time Tracker\\n       Tasks and projects: Organise your day with Focus To-Do and complete your to do, study, work, homework or housework you need to get done.\\n       Recurring tasks: Build lasting habits with powerful recurring due dates like \\\"Every Monday\\\".\\n       Reminders: Setting a Reminder ensures you never forget important things ever again, you can set up recurring due dates to remind you each and every time. \\n       Sub-tasks: Break down your task into smaller, actionable items or add a checklist .\\n       Task Priority: Highlight your day’s most important To-Do with color-coded priority levels.\\n       Estimated Pomodoro Number: Estimate the workload or set a goal.\\n       Note: Record more detailed about the task.\\n\\n- Report: Detailed statistics of your time distribution, tasks completed.\\n       Support the calculation of the total time of Focus Time.\\n       Gantt Chart of the Focus Time.\\n       Statistics on completed To Do. \\n       Statistics on time distribution of project.\\n       Trend chart of the completed To Do and the focus time.\\n\\n-  All-Platform synchronization: View and manage your goals wherever you are for better goal achieving.\\n       Support seamless synchronization within iPhone、Mac、iPad、Apple Watch and other platforms.\\n \\n-  Various Reminding:\\n       Focus Timer finished alarm, vibration reminding.\\n       Various white noise to help you focus on work & study.\\n\\nContact Us: focustodo@163.com, reply within 24 hours.\\nWebsite: https://www.focustodo.cn\\nPomodoro ™ and Pomodoro Technique ® are registered trademarks of Francesco Cirillo. This app is not affiliated with Francesco Cirillo.\\n\\nUsers have been focused on our app for 200 million hours, join us and we help you to be focused and increase your productivity, reduce procrastination and anxiety.\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"artistId\": 966057212,\n\t\t\t\"artistName\": \"Shenzhen Tomato Software Technology Co., Ltd.\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Productivity\",\n\t\t\t\t\"Utilities\"\n\t\t\t],\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.macpomodoro\",\n\t\t\t\"version\": \"6.3\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"appletvScreenshotUrls\": [],\n\t\t\t\"supportedDevices\": [\n\t\t\t\t\"iPadMini4-iPadMini4\",\n\t\t\t\t\"iPadProSecondGen-iPadProSecondGen\",\n\t\t\t\t\"iPhone11-iPhone11\",\n\t\t\t\t\"iPad71-iPad71\",\n\t\t\t\t\"iPadMiniRetinaCellular-iPadMiniRetinaCellular\",\n\t\t\t\t\"iPhone8Plus-iPhone8Plus\",\n\t\t\t\t\"iPhone6sPlus-iPhone6sPlus\",\n\t\t\t\t\"iPadMini5-iPadMini5\",\n\t\t\t\t\"iPadProFourthGen-iPadProFourthGen\",\n\t\t\t\t\"iPhoneXS-iPhoneXS\",\n\t\t\t\t\"iPadAir3Cellular-iPadAir3Cellular\",\n\t\t\t\t\"iPadAir3-iPadAir3\",\n\t\t\t\t\"iPadMini4Cellular-iPadMini4Cellular\",\n\t\t\t\t\"iPadProCellular-iPadProCellular\",\n\t\t\t\t\"MacDesktop-MacDesktop\",\n\t\t\t\t\"iPadMini3-iPadMini3\",\n\t\t\t\t\"iPhoneXR-iPhoneXR\",\n\t\t\t\t\"iPhoneSE-iPhoneSE\",\n\t\t\t\t\"iPad611-iPad611\",\n\t\t\t\t\"iPhone7-iPhone7\",\n\t\t\t\t\"iPad73-iPad73\",\n\t\t\t\t\"iPad812-iPad812\",\n\t\t\t\t\"iPadAir2Cellular-iPadAir2Cellular\",\n\t\t\t\t\"iPhoneX-iPhoneX\",\n\t\t\t\t\"iPadMini5Cellular-iPadMini5Cellular\",\n\t\t\t\t\"iPadPro97-iPadPro97\",\n\t\t\t\t\"iPad834-iPad834\",\n\t\t\t\t\"iPadProSecondGenCellular-iPadProSecondGenCellular\",\n\t\t\t\t\"iPhone5s-iPhone5s\",\n\t\t\t\t\"iPad75-iPad75\",\n\t\t\t\t\"iPadMini3Cellular-iPadMini3Cellular\",\n\t\t\t\t\"iPad878-iPad878\",\n\t\t\t\t\"iPhone6-iPhone6\",\n\t\t\t\t\"iPadAir-iPadAir\",\n\t\t\t\t\"iPadPro97Cellular-iPadPro97Cellular\",\n\t\t\t\t\"iPadSeventhGen-iPadSeventhGen\",\n\t\t\t\t\"iPodTouchSixthGen-iPodTouchSixthGen\",\n\t\t\t\t\"iPhoneXSMax-iPhoneXSMax\",\n\t\t\t\t\"iPad612-iPad612\",\n\t\t\t\t\"iPadPro-iPadPro\",\n\t\t\t\t\"iPodTouchSeventhGen-iPodTouchSeventhGen\",\n\t\t\t\t\"iPhone11ProMax-iPhone11ProMax\",\n\t\t\t\t\"iPadMiniRetina-iPadMiniRetina\",\n\t\t\t\t\"iPad76-iPad76\",\n\t\t\t\t\"iPadProFourthGenCellular-iPadProFourthGenCellular\",\n\t\t\t\t\"iPadSeventhGenCellular-iPadSeventhGenCellular\",\n\t\t\t\t\"iPhoneSESecondGen-iPhoneSESecondGen\",\n\t\t\t\t\"iPad74-iPad74\",\n\t\t\t\t\"iPhone6s-iPhone6s\",\n\t\t\t\t\"iPhone7Plus-iPhone7Plus\",\n\t\t\t\t\"iPadAir2-iPadAir2\",\n\t\t\t\t\"iPad72-iPad72\",\n\t\t\t\t\"iPhone6Plus-iPhone6Plus\",\n\t\t\t\t\"iPadAirCellular-iPadAirCellular\",\n\t\t\t\t\"Watch4-Watch4\",\n\t\t\t\t\"iPhone8-iPhone8\",\n\t\t\t\t\"iPad856-iPad856\",\n\t\t\t\t\"iPhone11Pro-iPhone11Pro\"\n\t\t\t],\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple114/v4/95/33/5f/95335f94-26d3-3567-93ac-77d60ab821dd/pr_source.png/392x696bb.png\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple114/v4/03/53/b9/0353b9b1-ef2a-7ff1-a1b8-4124867af41b/pr_source.png/392x696bb.png\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple124/v4/ef/63/ce/ef63ce41-371a-2508-b101-fb99e9c7758f/pr_source.png/392x696bb.png\"\n\t\t\t],\n\t\t\t\"ipadScreenshotUrls\": [\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple114/v4/43/19/bb/4319bb4b-5700-0f6b-2c19-7bd386bf186c/pr_source.jpg/552x414bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple114/v4/5d/51/1a/5d511a30-7fab-fd18-6967-c0caf9674d55/pr_source.jpg/552x414bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple124/v4/42/50/53/425053d8-2b26-c28a-72db-40323cc62aeb/source/60x60bb.jpg\",\n\t\t\t\"artworkUrl512\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple124/v4/42/50/53/425053d8-2b26-c28a-72db-40323cc62aeb/source/512x512bb.jpg\",\n\t\t\t\"artworkUrl100\": \"https://is4-ssl.mzstatic.com/image/thumb/Purple124/v4/42/50/53/425053d8-2b26-c28a-72db-40323cc62aeb/source/100x100bb.jpg\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/kevin-reutter/id1273424431?uo=4\",\n\t\t\t\"isGameCenterEnabled\": true,\n\t\t\t\"advisories\": [],\n\t\t\t\"features\": [\n\t\t\t\t\"gameCenter\",\n\t\t\t\t\"iosUniversal\"\n\t\t\t],\n\t\t\t\"kind\": \"software\",\n\t\t\t\"minimumOsVersion\": \"13.0\",\n\t\t\t\"trackName\": \"Planny 3 - Smart To Do List\",\n\t\t\t\"trackId\": 1289070327,\n\t\t\t\"sellerName\": \"Kevin Reutter\",\n\t\t\t\"releaseNotes\": \"Stay tuned! Planny 4 ships in a few week and will be a free update with many great features!\\n\\n• SwiftUI \\nNow Planny uses SwiftUI in some parts of the app. SwiftUI is an innovative, exceptionally simple way to build user interfaces across all Apple platforms with the power of Swift. Over time more and more of the app will be created with SwiftUI to avoid crashes and improve performance. \\n\\n• Advanced Cursor Support\\nWhen using a Trackpad on iPadOS or on the Mac, specific Elements become larger when you come closer to make clicking easier\\n\\n• Alternative App icons\\nChoose the icon color you’d like in settings (iOS for iPhone only)\\n\\n• New Onboarding Experience\\nA new tutorial shows the key features \\n\\n• New Purchase View\\nThe purchase view is now much simpler. Feel free to subscribe :) \\n\\n• Fixed deadlines on macOS\\n• Direct Deadlines now support days and time \\n• Fixed issues with overdue tasks \\n\\nDo you have any wishes for Planny 4? Feel free to submit ideas on the website!\",\n\t\t\t\"primaryGenreId\": 6007,\n\t\t\t\"primaryGenreName\": \"Productivity\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"releaseDate\": \"2017-10-13T19:16:40Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6007\",\n\t\t\t\t\"6002\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-07-30T17:37:31Z\",\n\t\t\t\"trackCensoredName\": \"Planny 3 - Smart To Do List\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\",\n\t\t\t\t\"FR\",\n\t\t\t\t\"DE\",\n\t\t\t\t\"IT\",\n\t\t\t\t\"RU\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"ES\",\n\t\t\t\t\"TR\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"47687680\",\n\t\t\t\"sellerUrl\": \"https://www.kevinreutter.de/planny-3/\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 4.3897300000000001318767317570745944976806640625,\n\t\t\t\"userRatingCountForCurrentVersion\": 331,\n\t\t\t\"averageUserRating\": 4.3897300000000001318767317570745944976806640625,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/planny-3-smart-to-do-list/id1289070327?uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"++ Planny was part of Apples favorite Apps from October ++\\n\\nPlanny is all new and has been rethought from the ground up.\\n\\nPlanny is your new friend helping you to be more productive. Planny learned everything important from common to do list apps but combines them with intelligence and gamification. In the morning and during the day Planny intelligently recommends tasks and also reminds you if you tend to forget them. You earn productivity points for adding and completing tasks, and also lose them if you shift tasks or forget them. Users can compare their productivity with friends over the week. \\n\\nPlanny also features all the important features like deadlines, lists / projects, tagging, location based reminders, notes and attachments, routines and more. \\n\\nKey features\\n• Daily list to focus on today's tasks\\n• Assistant for creating a productive daily plan\\n• Daily review of the last day\\n• Routines to train your habits\\n• Deadlines and reminders\\n• Smart reminders if you tend to forget your tasks\\n• Notes for your tasks\\n• Weekly productivity ranking of your contacts\\n• Rewards\\n• Dark mode\\n• Lists\\n• Siri support\\n• Advanced Apple Watch app\\n\\nPlanny Premium offers additional features like:\\n• Calendar view\\n• Teamwork with your friends\\n• Add Photos from your library to tasks\\n• Add Photos from your camera to tasks\\n• Location based reminders\\n• iCloud sync\\n• iCloud backup \\n• FaceID Unlock\\n• More than 2 lists\\n• Printing\\n• Sketches\\n• Review your recent days\\n• Tagging\\n\\n+++ Planny Premium - Unlock all features and use Planny on iPhone, iPad and Apple Watch (Mac soon) - And get free feature updates over time! +++ \\n\\nA Planny Premium subscription unlocks all features. Note that iCloud features require an iCloud-Account. \\n\\nPlanny offers two auto-renewing subscriptions\\n\\nPremium 3 Months\\n$6,99 / 3 Months (may differ in your country & currency)\\n\\nPremium Annual\\n$19,99 / Year  (may differ in your country & currency)\\n\\nPayment will be charged to iTunes Account at confirmation of purchase\\nSubscription automatically renews unless auto-renew is turned off at least 24-hours before the end of the current period\\nAccount will be charged for renewal within 24-hours prior to the end of the current period, and identify the cost of the renewal\\n\\nSubscriptions may be managed by the user and auto-renewal may be turned off by going to the user's Account Settings after purchase\\n\\nWhen your subscription is cancelled and expires, all the features of Planny Pro won't be available any longer. Any unused portion of a free trial period, if offered, will be forfeited when the user purchases a subscription to that publication, where applicable.\\n\\nPrivacy policy for Planny: https://kevinreutter.de/privacy\\nTerms of use / Conditions: https://kevinreutter.de/privacy\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"artistId\": 1273424431,\n\t\t\t\"artistName\": \"Kevin Reutter\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Productivity\",\n\t\t\t\t\"Utilities\"\n\t\t\t],\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.kevinreutter.Callisto\",\n\t\t\t\"version\": \"3.4.2\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 331\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple/v4/4f/ff/f9/4ffff968-2932-48af-431f-fd1b086026cf/mzl.srudbvwp.png/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple4/v4/2a/4f/9f/2a4f9fad-c1a7-fa80-56d7-fea2d3beaa0a/mzl.dcyubghz.png/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple6/v4/56/3a/a7/563aa771-8288-e21a-cfe8-e28e77ffad83/mzl.lzjpfyct.png/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple4/v4/1e/8d/4e/1e8d4eaa-17f7-5295-1f36-975b62164d19/mzl.yufjavxy.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple4/v4/fb/9b/85/fb9b851d-6ef5-792f-0945-ff2f1a78ce7a/mzl.gycjiioz.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple3/v4/6b/67/f2/6b67f2d4-2603-ec03-504c-fd408d3577d7/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple3/v4/6b/67/f2/6b67f2d4-2603-ec03-504c-fd408d3577d7/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple3/v4/6b/67/f2/6b67f2d4-2603-ec03-504c-fd408d3577d7/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/antlogic/id364746702?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"minimumOsVersion\": \"10.6.6\",\n\t\t\t\"trackName\": \"To-do Lists\",\n\t\t\t\"trackId\": 416993121,\n\t\t\t\"sellerName\": \"Mykola Olshevskyi\",\n\t\t\t\"releaseNotes\": \"fixed accidentally broken compatibility for Mac OS 10.6-10.7\",\n\t\t\t\"primaryGenreId\": 6007,\n\t\t\t\"primaryGenreName\": \"Productivity\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"releaseDate\": \"2011-03-01T03:09:22Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6007\",\n\t\t\t\t\"6000\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"$4.99\",\n\t\t\t\"currentVersionReleaseDate\": \"2015-04-16T19:07:37Z\",\n\t\t\t\"trackCensoredName\": \"To-do Lists\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\",\n\t\t\t\t\"FR\",\n\t\t\t\t\"DE\",\n\t\t\t\t\"RU\",\n\t\t\t\t\"UK\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"2095731\",\n\t\t\t\"sellerUrl\": \"https://www.antlogic.com/#to-do-lists\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/to-do-lists/id416993121?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"To-do Lists provides simple but powerful interface for tasks management.\\n\\nTo-do Lists features:\\n- Quick, one-click tasks addition/removal.\\n- Rich-text editing, in-text links support.\\n- Seamless iCloud Reminders synchronization.\\n- DropBox synchronization between computers and To-do Lists Mobile for iOS\\n- Import/export of to-do lists via text files.\\n- Printing of to-do lists or mailing them directly from the application.\\n- Backup and restore of whole to-do database.\\n- Full drag'n'drop support (make new to-do from web link, file, document, e-mail, or any other text by simply dropping them on to-do list).\\n- System services support (make new to-do from any text in any application).\\n- Rolled-up, translucent or floating to-do lists.\\n- Customized background color, text color, font and checkbox appearance.\\n- Reminders.\\n- Quick-access icon in system menu.\\n\\nTo-do Lists usage video:\\nhttps://www.youtube.com/watch?v=5KB-4sYcelo (or https://www.youtube.com/AntlogicCompany )\\n\\nFor more information, visit our site at https://www.antlogic.com\\nor Facebook page:\\nhttps://www.facebook.com/AntlogicCompany\\n\\nIf you have any problems or questions using To-do Lists - visit our support forums at https://www.antlogic.com/#contact-us\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"artistId\": 364746702,\n\t\t\t\"artistName\": \"AntLogic\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Productivity\",\n\t\t\t\t\"Business\"\n\t\t\t],\n\t\t\t\"price\": 4.99,\n\t\t\t\"bundleId\": \"ua.com.AntLogic.ToDoLists\",\n\t\t\t\"version\": \"1.7.7\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/a8/e9/42/a8e942ec-8eea-03b3-ea37-cc6e2837fb5e/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/5f/62/5c/5f625c38-c559-3b8d-5042-94e241735ef1/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/aa/a1/e7/aaa1e746-e660-2b6e-6833-d751e7879752/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/c0/6f/7d/c06f7de4-17b9-7475-8778-22a97c13cdce/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/84/3d/8d/843d8de0-6257-7bf0-6a66-6f3ce41af803/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/ad/0d/28/ad0d28c6-ff1d-c394-266a-fdff0b8e9cc6/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/36/28/a3/3628a3e9-6073-0ce4-17d7-9d9a5f479c64/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/a9/ac/b9/a9acb983-76e2-d76d-fbc8-c35388dcee48/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple113/v4/8f/41/90/8f4190f5-ebb8-370b-c8a6-afb47c56140d/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple123/v4/09/37/83/09378396-de11-2185-24f4-360be20dbcac/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple124/v4/71/6f/f0/716ff030-f8ec-536c-41ca-f5116ae1f497/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple124/v4/71/6f/f0/716ff030-f8ec-536c-41ca-f5116ae1f497/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple124/v4/71/6f/f0/716ff030-f8ec-536c-41ca-f5116ae1f497/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/the-omni-group/id281731738?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"minimumOsVersion\": \"10.14\",\n\t\t\t\"trackName\": \"OmniFocus 3\",\n\t\t\t\"trackId\": 1346203938,\n\t\t\t\"sellerName\": \"The Omni Group\",\n\t\t\t\"releaseNotes\": \"OmniFocus 3.9.2 is a minor update focused on bug fixes.\\n\\n• Omni Automation — OmniFocus now recognizes simple plug-ins that use the .omnifocusjs file extention.\\n• First Run — Improved reliability of the first run flow.\\n• Notice Bar — Fixed bugs related to the Trial Mode & Free Viewer notice bars.\\n\\nIf you have any feedback or questions, we’d love to hear from you! The Omni Group offers free tech support; you can email omnifocus@omnigroup.com, call 1–800–315–6664 or 1–206–523–4152, or tweet @OmniFocus.\\n\\nIf OmniFocus empowers you, we would appreciate an App Store review. Your review will help other people find OmniFocus and make them more productive too.\",\n\t\t\t\"primaryGenreId\": 6007,\n\t\t\t\"primaryGenreName\": \"Productivity\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"releaseDate\": \"2018-09-24T12:28:36Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6007\",\n\t\t\t\t\"6000\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-08-27T17:54:49Z\",\n\t\t\t\"trackCensoredName\": \"OmniFocus 3\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"NL\",\n\t\t\t\t\"EN\",\n\t\t\t\t\"FR\",\n\t\t\t\t\"DE\",\n\t\t\t\t\"IT\",\n\t\t\t\t\"JA\",\n\t\t\t\t\"KO\",\n\t\t\t\t\"PT\",\n\t\t\t\t\"RU\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"ES\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"64931473\",\n\t\t\t\"sellerUrl\": \"https://www.omnigroup.com/omnifocus/\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/omnifocus-3/id1346203938?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Two-week free trial! OmniFocus Standard and Pro are in-app purchases, with discounts for people who bought earlier versions of OmniFocus for Mac through the Mac App Store. Or you can get OmniFocus for iOS, Mac, and web for just one price with the OmniFocus Subscription. Download the app for details.\\n\\nUse OmniFocus to accomplish more every day. Create projects and tasks, organize them with tags, focus on what you can do right now — and get stuff done.\\n\\nOmniFocus — now celebrating 10 years as the trusted, gold-standard to-do list app — brings unrivaled power and flexibility to your Mac, making it easy to work the way you want to work.\\n\\nOmniFocus manages everything in your busy life. Use projects to organize tasks naturally, and then add tags to organize across projects. Easily enter tasks when you’re on the go, and process them when you have time. Tap the Forecast view — which shows both tasks and calendar events — to get a handle on your day. Use the Review perspective to keep your projects and tasks on track.\\n\\nThen let our free syncing system make sure your data is the same on every Mac. (And on OmniFocus for iOS and Web, available separately.) Because your data is encrypted, it’s safe in the cloud.\\n\\nSTANDARD FEATURES (VIA IN-APP PURCHASE)\\n\\n• NEW: Tags add a powerful additional organizing tool. Create tags for people, energy levels, priorities, locations, and more.\\n• NEW: The Forecast view shows your tasks and calendar events in order, so you can better see what’s coming up in your day.\\n• NEW: Enhanced repeating tasks are easier than ever to set up — and they work with real-world examples such as the first weekday of the month.\\n• NEW: The Modern, fresh-but-familiar design helps you focus on your content.\\n• Inbox is where you quickly add tasks — save them when you think of them, and organize them later.\\n• Syncing supports end-to-end encryption so that your data is safe wherever it’s stored, on our server or yours.\\n• Notes can be attached to your tasks, so you have all the information you need.\\n• Attachments — graphics, video, audio, whatever you want — add richness to your tasks.\\n• View Options let you customize each perspective by deciding what it should show and how it should filter your tasks.\\n• The Review perspective takes you through your projects and tasks — so you stay on track.\\n• OmniFocus Mail Drop adds tasks via email and works with services like IFTTT and Zapier (if you’re using our free syncing server).\\n• The Today Widget shows you your most important items — you don’t even have to switch to the app to know what’s up.\\n• Support for TaskPaper Text and omnifocus:///add and /paste lets you automate using URLs.\\n\\nPro features make OmniFocus even more powerful:\\n\\nPRO FEATURES (VIA IN-APP PURCHASE)\\n\\n• Custom perspectives help you create new ways to see your data by filtering and grouping projects and tags. NEW: The filtering rules are simpler to use while being more powerful than ever, letting you combine rules with “all,” “any,” and “none.” You can also choose any image to use as your custom perspective’s icon, and a custom tint color to go with it.\\n• NEW: Today’s Forecast can include items with a specific tag, and you can reorder those tasks however you choose, so you can plan your day better.\\n• The customizable sidebar lets you organize your perspectives the way you want to, for super-fast access.\\n• The Today Widget shows a perspective of your choice in Notification Center.\\n• AppleScript support opens up a world of automation, using Apple’s Mac scripting language.\\n\\nDownload OmniFocus right now and start your free trial! The app includes a manual, and there’s plenty more documentation on the website.\\n\\nSUPPORT\\n\\nIf you have feedback or questions, our Support Humans would love to hear from you! Send email to omnifocus@omnigroup.com, call us at at 1-800-315-6664 or +1-206-523-4152, or reach us on Twitter at @omnifocus.\\n\\n\\nSubscription Terms of Service: https://www.omnigroup.com/legal\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"artistId\": 281731738,\n\t\t\t\"artistName\": \"The Omni Group\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Productivity\",\n\t\t\t\t\"Business\"\n\t\t\t],\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.omnigroup.OmniFocus3.MacAppStore\",\n\t\t\t\"version\": \"3.9.2\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple114/v4/1a/72/1d/1a721d98-fbc4-ed9e-2aae-ef9d5b538693/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple124/v4/a2/b1/10/a2b110fd-aa90-286a-658b-2abd85bd1c68/mzl.menowpkq.png/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple114/v4/26/f3/32/26f3322f-8ef9-6171-2864-715f571300e6/mzl.qxibkqwt.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple124/v4/a4/1b/12/a41b12dc-6e1d-74ff-7ad3-1d6888c31462/mzl.fdlcjqnh.png/800x500bb.jpg\",\n\t\t\t\t\"https://is2-ssl.mzstatic.com/image/thumb/Purple124/v4/83/83/24/83832412-85d1-78ff-a9ab-86a37b31121d/mzl.ateekpxr.png/800x500bb.jpg\",\n\t\t\t\t\"https://is1-ssl.mzstatic.com/image/thumb/Purple114/v4/e6/7c/c7/e67cc703-d274-a1fc-88af-b5a8ce9cbfd8/mzl.grtjmgef.png/800x500bb.jpg\",\n\t\t\t\t\"https://is4-ssl.mzstatic.com/image/thumb/Purple124/v4/18/a8/f2/18a8f211-61b5-7b7e-b343-784b260de31d/mzl.ulsghntx.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is2-ssl.mzstatic.com/image/thumb/Purple114/v4/5a/cf/6c/5acf6c83-c496-d5fb-2445-96ef44f13a82/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is2-ssl.mzstatic.com/image/thumb/Purple114/v4/5a/cf/6c/5acf6c83-c496-d5fb-2445-96ef44f13a82/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is2-ssl.mzstatic.com/image/thumb/Purple114/v4/5a/cf/6c/5acf6c83-c496-d5fb-2445-96ef44f13a82/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/masterbuilders/id896347016?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"minimumOsVersion\": \"10.14\",\n\t\t\t\"trackName\": \"Focus - Time Management\",\n\t\t\t\"trackId\": 777233759,\n\t\t\t\"sellerName\": \"Masterbuilders\",\n\t\t\t\"releaseNotes\": \"Subscription status is now properly unlocked on all devices.\",\n\t\t\t\"primaryGenreId\": 6007,\n\t\t\t\"primaryGenreName\": \"Productivity\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"releaseDate\": \"2013-12-19T19:16:50Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6007\",\n\t\t\t\t\"6017\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-02-12T20:37:50Z\",\n\t\t\t\"trackCensoredName\": \"Focus - Time Management\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\",\n\t\t\t\t\"FR\",\n\t\t\t\t\"DE\",\n\t\t\t\t\"JA\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"ES\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"24637530\",\n\t\t\t\"sellerUrl\": \"https://www.focusapp.io\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/focus-time-management/id777233759?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"Meet Focus: the best time manager for iPhone, iPad, Apple Watch and Mac. Focus is the most elegant and professional way to get more wore done, working in highly efficient work sessions, one task at a time.\\n\\n“[…] a tool that can genuinely make people more productive\\\" – MacStories.net\\n\\n“[…] a must-have for anyone who finds themselves easily getting distracted or forgetting to take occasional breaks.\\\" – iDownloadBlog.com\\n\\n======================\\nFEATURES\\n======================\\n\\nFOCUS SESSIONS\\nFocus Sessions are a highly efficient way to work. Focus for 25 minutes, then take a short break to relax your mind. After four sessions, take a 15 to 20 minute break. This method maximizes energy, stimulates creativity and promotes a sense of achievement.\\n\\nTASK MANAGER\\nFocus includes a lightweight task manager that lets you organize the things you want to work on intuitively. By working on one task at a time, you won’t be distracted and can focus all your attention towards completing that goal. That way you’ll be perfectly organized on your path to success.\\n\\nIN-DEPTH STATISTICS\\nCheck what you’ve already done! Focus keeps track of your work and offers in-depth and motivating statistics. See your daily, weekly and monthly activity so you don’t lose sight of the big picture. \\n\\nFOCUS EVERYWHERE\\nSeamlessly use Focus on your Mac, iPad, iPhone, and Apple Watch. Sync across your devices using iCloud; use Handoff to pick up your current work on another device and get up-to-the-second data with iCloud Push. You can also use the Today widget to quickly glance at your progress, import tasks using the handy Action extension, and more.\\n\\nFOCUS & APPLE WATCH: A PERFECT FIT\\nUsing Focus on your wrist is a natural fit. The independent Apple Watch app is made for for easy and lightweight interactions that lets you control sessions and track your progress throughout the day. With the Focus complication, you can customize your watch face to see your current progress at a glance.\\n\\nBEAUTIFUL INTERFACE\\nThe name says it all: Focus draws your attention to the most important things. It’s designed to be unobtrusive, accessible and easy-to-use. You’ll intuitively master its collection of features just by using them.\\n\\n======================\\nSUBSCRIPTION PRICING\\n======================\\n\\nFocus offers two subscription options: \\nFocus Monthly at $4.99/ month \\nFocus Yearly at $39.99/ year\\n\\nThe subscription unlocks all features on all devices (Mac, iPhone, iPad and Apple Watch).\\n\\nTRY IT FREE \\nFocus Monthly comes with a 3-day free trial period, Focus Yearly with a 7-day free trial period. If you cancel before the end of the trial, you will not be charged for the subscription.\\n\\nSUBSCRIPTION TERMS\\nPayment will be charged to your Apple ID account at the confirmation of purchase or after the free trial period if offered. \\n\\nYou subscription will automatically renew unless it is canceled at least 24 hours before the end of the current period. Your account will be charged 24 hours prior to the end of the current period. \\n\\nYou can manage and cancel your subscriptions by going to your account settings in the App Store after purchase. Any unused portion of a free trial will be forfeited when you purchase a subscription\\n\\n======================\\nCONTACT\\n======================\\n\\nIf you have any questions or ideas, please write us at hello@masterbuilders.io\\n\\nTwitter: @focusappio\\nhttps://www.masterbuilders.io\\n\\n\\n\\nPrivacy Policy: https://www.masterbuilders.io/privacy\\nTerms of Service: https://www.masterbuilders.io/terms\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"artistId\": 896347016,\n\t\t\t\"artistName\": \"Masterbuilders\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Productivity\",\n\t\t\t\t\"Education\"\n\t\t\t],\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.malteundjan.focus-osx\",\n\t\t\t\"version\": \"6.2.3\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t},\n\t\t{\n\t\t\t\"screenshotUrls\": [\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple124/v4/35/03/5a/35035a62-e2da-2f4b-6ece-63475bd7cd02/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is3-ssl.mzstatic.com/image/thumb/Purple124/v4/b5/ac/1f/b5ac1fe2-431d-e45d-63e0-57ddbfbd525f/pr_source.png/800x500bb.jpg\",\n\t\t\t\t\"https://is5-ssl.mzstatic.com/image/thumb/Purple114/v4/6c/18/ee/6c18eeff-ca66-2b01-82f3-f81576336ab7/pr_source.png/800x500bb.jpg\"\n\t\t\t],\n\t\t\t\"artworkUrl60\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple114/v4/12/30/fb/1230fb0c-42fd-1a80-9379-29be0ba0f612/source/60x60bb.png\",\n\t\t\t\"artworkUrl512\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple114/v4/12/30/fb/1230fb0c-42fd-1a80-9379-29be0ba0f612/source/512x512bb.png\",\n\t\t\t\"artworkUrl100\": \"https://is3-ssl.mzstatic.com/image/thumb/Purple114/v4/12/30/fb/1230fb0c-42fd-1a80-9379-29be0ba0f612/source/100x100bb.png\",\n\t\t\t\"artistViewUrl\": \"https://apps.apple.com/us/developer/niklas-behrens/id969210609?mt=12&uo=4\",\n\t\t\t\"kind\": \"mac-software\",\n\t\t\t\"minimumOsVersion\": \"10.10\",\n\t\t\t\"trackName\": \"1Focus: Website & App Blocker\",\n\t\t\t\"trackId\": 969210610,\n\t\t\t\"sellerName\": \"Niklas Behrens\",\n\t\t\t\"releaseNotes\": \"- Allows updating 1Focus while blocking is active\\n- Fixed toolbar overflow on macOS High Sierra\\n- Improved status item width\\n- Fixed quick start menu starting wrong task\\n- Other bug fixes\",\n\t\t\t\"primaryGenreId\": 6007,\n\t\t\t\"primaryGenreName\": \"Productivity\",\n\t\t\t\"isVppDeviceBasedLicensingEnabled\": true,\n\t\t\t\"releaseDate\": \"2015-03-15T05:54:46Z\",\n\t\t\t\"genreIds\": [\n\t\t\t\t\"6007\",\n\t\t\t\t\"6017\"\n\t\t\t],\n\t\t\t\"formattedPrice\": \"Free\",\n\t\t\t\"currentVersionReleaseDate\": \"2020-07-18T23:51:25Z\",\n\t\t\t\"trackCensoredName\": \"1Focus: Website & App Blocker\",\n\t\t\t\"languageCodesISO2A\": [\n\t\t\t\t\"EN\",\n\t\t\t\t\"FR\",\n\t\t\t\t\"DE\",\n\t\t\t\t\"JA\",\n\t\t\t\t\"KO\",\n\t\t\t\t\"RU\",\n\t\t\t\t\"ZH\",\n\t\t\t\t\"ES\"\n\t\t\t],\n\t\t\t\"fileSizeBytes\": \"8338821\",\n\t\t\t\"sellerUrl\": \"https://onefocusapp.com\",\n\t\t\t\"contentAdvisoryRating\": \"4+\",\n\t\t\t\"averageUserRatingForCurrentVersion\": 0,\n\t\t\t\"userRatingCountForCurrentVersion\": 0,\n\t\t\t\"averageUserRating\": 0,\n\t\t\t\"trackViewUrl\": \"https://apps.apple.com/us/app/1focus-website-app-blocker/id969210610?mt=12&uo=4\",\n\t\t\t\"trackContentRating\": \"4+\",\n\t\t\t\"description\": \"1Focus creates an oasis for focused work by disabling access to specific websites and apps. Use it to schedule a bit of automated self-restraint when you find yourself clicking away from what really needs to get done. Ideal for students, freelancers and writers.\\n\\n\\\"If you find yourself on Facebook or checking your email every five minutes, you need 1Focus.\\\" – Pagoda Technologies\\n\\n\\\"1Focus is one of the best apps for tuning out the diversions that are most distracting for you.\\\" – Tyler Horvath, CEO of Tyton Media\\n\\n\\nFREE FEATURES\\n\\n• Block websites in Google Chrome, Safari, Opera, Microsoft Edge and Brave\\n• Block apps (e.g. email, games)\\n• Block internet access by blocking web browsers\\n• You cannot cancel active blocks once you close the 1Focus window\\n• Create your own task presets (up to 2)\\n• Dark Mode\\n\\n\\n1FOCUS PRO\\n\\n• Schedule recurring block events (e.g. Mon - Fri)\\n• Work break timer\\n• Unlimited task presets\\n• Block all websites/apps except specific ones\\n• Suspend blocking for a limited time\\n• Block URL keywords (e.g. *gaming*)\\n• Block popular websites by category (e.g. Social Media)\\n\\nTry it free for 14 days. $1.99/month or $9.99/year after.\\n\\nPrices may vary by location. Subscriptions are charged to your iTunes Account. They automatically renew unless you cancel them in your Account Settings at least 24 hours before the end of the current period. Your Account is charged for renewal within 24 hours prior to the end of the current period. Terms of use: https://onefocusapp.com/terms\\n\\n\\nCUSTOMER SUPPORT\\n\\nDo you have any questions or suggestions?\\nonefocusapp.com/support\",\n\t\t\t\"currency\": \"USD\",\n\t\t\t\"artistId\": 969210609,\n\t\t\t\"artistName\": \"Niklas Behrens\",\n\t\t\t\"genres\": [\n\t\t\t\t\"Productivity\",\n\t\t\t\t\"Education\"\n\t\t\t],\n\t\t\t\"price\": 0.00,\n\t\t\t\"bundleId\": \"com.onefocusapp.OneFocus\",\n\t\t\t\"version\": \"3.4.4\",\n\t\t\t\"wrapperType\": \"software\",\n\t\t\t\"userRatingCount\": 0\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "Tests/MASTests/Utilities/Consequences.swift",
    "content": "//\n// Consequences.swift\n// mas\n//\n// Copyright © 2024 mas-cli. All rights reserved.\n//\n\ninternal import Foundation\n@testable private import mas\n\nstruct Consequences<Value> {\n\tlet value: Value?\n\tlet error: (any Error)?\n\tlet stdout: String\n\tlet stderr: String\n\n\tinit(_ error: (any Error)? = nil, _ stdout: String = \"\", _ stderr: String = \"\") where Value == NoValue {\n\t\tself.init(nil, error, stdout, stderr)\n\t}\n\n\tinit(_ value: Value?, _ error: (any Error)? = nil, _ stdout: String = \"\", _ stderr: String = \"\") {\n\t\tself.value = value\n\t\tself.error = error\n\t\tself.stdout = stdout\n\t\tself.stderr = stderr\n\t}\n}\n\nextension Consequences: Equatable where Value: Equatable { // swiftlint:disable:this file_types_order\n\tstatic func == (lhs: Self, rhs: Self) -> Bool {\n\t\tguard lhs.value == rhs.value, lhs.stdout == rhs.stdout, lhs.stderr == rhs.stderr else {\n\t\t\treturn false\n\t\t}\n\n\t\treturn switch (lhs.error, rhs.error) {\n\t\tcase (nil, nil):\n\t\t\ttrue\n\t\tcase let (lhsError?, rhsError?):\n\t\t\t(lhsError as NSError) == (rhsError as NSError)\n\t\tdefault:\n\t\t\tfalse\n\t\t}\n\t}\n}\n\nprivate struct StandardStreamCapture { // swiftlint:disable:this one_declaration_per_file\n\tprivate let encoding: String.Encoding\n\tprivate let outOriginalFD: Int32\n\tprivate let errOriginalFD: Int32\n\tprivate let outDuplicateFD: Int32\n\tprivate let errDuplicateFD: Int32\n\tprivate let outPipe: Pipe\n\tprivate let errPipe: Pipe\n\n\tinit(encoding: String.Encoding) {\n\t\tself.encoding = encoding\n\n\t\toutOriginalFD = FileHandle.standardOutput.fileDescriptor\n\t\terrOriginalFD = FileHandle.standardError.fileDescriptor\n\n\t\toutDuplicateFD = dup(outOriginalFD)\n\t\terrDuplicateFD = dup(errOriginalFD)\n\n\t\toutPipe = Pipe()\n\t\terrPipe = Pipe()\n\n\t\tdup2(outPipe.fileHandleForWriting.fileDescriptor, outOriginalFD)\n\t\tdup2(errPipe.fileHandleForWriting.fileDescriptor, errOriginalFD)\n\t}\n\n\tfunc consequences(value _: Void, error: (any Error)? = nil) -> Consequences<NoValue> {\n\t\tlet (stdout, stderr) = finishAndRead(encoding: encoding)\n\t\treturn .init(nil as NoValue?, error, stdout, stderr)\n\t}\n\n\tfunc consequences<Value>(value: Value? = nil, error: (any Error)? = nil) -> Consequences<Value> {\n\t\tlet (stdout, stderr) = finishAndRead(encoding: encoding)\n\t\treturn .init(value, error, stdout, stderr)\n\t}\n\n\tprivate func finishAndRead(encoding: String.Encoding) -> (stdout: String, stderr: String) {\n\t\tunsafe fflush(stdout)\n\t\tunsafe fflush(stderr)\n\t\tdup2(outDuplicateFD, outOriginalFD)\n\t\tdup2(errDuplicateFD, errOriginalFD)\n\t\ttry? outPipe.fileHandleForWriting.close()\n\t\ttry? errPipe.fileHandleForWriting.close()\n\n\t\tclose(outDuplicateFD)\n\t\tclose(errDuplicateFD)\n\n\t\treturn (try! outPipe.readToEnd(encoding: encoding) ?? \"\", try! errPipe.readToEnd(encoding: encoding) ?? \"\")\n\t} // swiftlint:disable:previous force_try\n}\n\nenum NoValue: Equatable { // swiftlint:disable:this one_declaration_per_file\n\t// Empty\n}\n\nfunc consequencesOf(encoding: String.Encoding = .utf8, _ body: @autoclosure () throws -> Void)\n-> Consequences<NoValue> { // swiftformat:disable:this indent\n\tlet capture = StandardStreamCapture(encoding: encoding)\n\tdo {\n\t\treturn capture.consequences(value: try body())\n\t} catch {\n\t\treturn capture.consequences(error: error)\n\t}\n}\n\nfunc consequencesOf(encoding: String.Encoding = .utf8, _ body: @autoclosure () async throws -> Void)\nasync -> Consequences<NoValue> { // swiftformat:disable:this indent\n\tlet capture = StandardStreamCapture(encoding: encoding)\n\tdo {\n\t\treturn capture.consequences(value: try await body())\n\t} catch {\n\t\treturn capture.consequences(error: error)\n\t}\n}\n\nfunc consequencesOf<Value>(encoding: String.Encoding = .utf8, _ body: @autoclosure () throws -> Value?)\n-> Consequences<Value> { // swiftformat:disable:this indent\n\tlet capture = StandardStreamCapture(encoding: encoding)\n\tdo {\n\t\treturn capture.consequences(value: try body())\n\t} catch {\n\t\treturn capture.consequences(error: error)\n\t}\n}\n\nfunc consequencesOf<Value>(encoding: String.Encoding = .utf8, _ body: @autoclosure () async throws -> Value?)\nasync -> Consequences<Value> { // swiftformat:disable:this indent\n\tlet capture = StandardStreamCapture(encoding: encoding)\n\tdo {\n\t\treturn capture.consequences(value: try await body())\n\t} catch {\n\t\treturn capture.consequences(error: error)\n\t}\n}\n"
  },
  {
    "path": "contrib/completion/mas-completion.bash",
    "content": "#!/usr/bin/env bash\n\n_mas() {\n\tlocal cur prev words cword\n\tif declare -F _init_completions >/dev/null 2>&1; then\n\t\t_init_completion\n\telse\n\t\tCOMPREPLY=()\n\t\t_get_comp_words_by_ref cur prev words cword\n\tfi\n\tif [[ \"${cword}\" -eq 1 ]]; then\n\t\tlocal -r ifs_old=\"${IFS}\"\n\t\tIFS=$'\\n'\n\t\tlocal -a mas_help=($(mas help))\n\t\tmas_help=(\"${mas_help[@]:5:${#mas_help[@]}-6}\")\n\t\tmas_help=(\"${mas_help[@]#  }\")\n\t\tlocal -a commands=(help)\n\t\tfor line in \"${mas_help[@]}\"; do\n\t\t\tif [[ ! \"${line}\" =~ ^\\  ]]; then\n\t\t\t\tcommands+=(\"${line%% *}\")\n\t\t\tfi\n\t\tdone\n\t\tCOMPREPLY=($(compgen -W \"${commands[*]}\" -- \"${cur}\"))\n\t\tIFS=\"${ifs_old}\"\n\t\treturn 0\n\tfi\n}\n\ncomplete -F _mas mas\n"
  },
  {
    "path": "contrib/completion/mas.fish",
    "content": "# fish completions for mas\n\nfunction __fish_mas_list_available -d \"Lists applications available to install from the App Store\"\n\tset query (commandline -ct)\n\tif set results (command mas search \"$query\" 2>/dev/null)\n\t\tfor res in $results\n\t\t\techo \"$res\"\n\t\tend | string trim --left | string replace -r '\\s+' '\\t'\n\tend\nend\n\nfunction __fish_mas_list_installed -d \"Lists installed applications from the App Store\"\n\tcommand mas list 2>/dev/null | string replace -r '\\s+' '\\t'\nend\n\nfunction __fish_mas_outdated_installed -d \"Lists outdated installed applications from the App Store\"\n\tcommand mas outdated 2>/dev/null | string replace -r '\\s+' '\\t'\nend\n\n# no file completions in mas\ncomplete -c mas -f\n\n### account\ncomplete -c mas -n \"__fish_use_subcommand\" -f -a account -d \"Output the Apple Account signed in to the App Store\"\ncomplete -c mas -n \"__fish_seen_subcommand_from help\" -xa \"account\"\n### config\ncomplete -c mas -n \"__fish_use_subcommand\" -f -a config -d \"Output mas config & related system info\"\ncomplete -c mas -n \"__fish_seen_subcommand_from help\" -xa \"config\"\ncomplete -c mas -n \"__fish_seen_subcommand_from config\" -l markdown -d \"Output as Markdown\"\n### get\ncomplete -c mas -n \"__fish_use_subcommand\" -f -a get -d \"Get & install free apps from the App Store\"\ncomplete -c mas -n \"__fish_seen_subcommand_from help\" -xa \"get\"\n### help\ncomplete -c mas -n \"__fish_use_subcommand\" -f -a help -d \"Output general or command-specific help\"\ncomplete -c mas -n \"__fish_seen_subcommand_from help\" -xa \"help\"\n### home\ncomplete -c mas -n \"__fish_use_subcommand\" -f -a home -d \"Open App Store app pages in the default web browser\"\ncomplete -c mas -n \"__fish_seen_subcommand_from help\" -xa \"home\"\ncomplete -c mas -n \"__fish_seen_subcommand_from get home install lookup open seller\" -xa \"(__fish_mas_list_available)\"\n### install\ncomplete -c mas -n \"__fish_use_subcommand\" -f -a install -d \"Install previously gotten apps from the App Store\"\ncomplete -c mas -n \"__fish_seen_subcommand_from help\" -xa \"install\"\ncomplete -c mas -n \"__fish_seen_subcommand_from install lucky\" -l force -d \"Force reinstall\"\n### list\ncomplete -c mas -n \"__fish_use_subcommand\" -f -a list -d \"List all apps installed from the App Store\"\ncomplete -c mas -n \"__fish_seen_subcommand_from help\" -xa \"list\"\n### lookup\ncomplete -c mas -n \"__fish_use_subcommand\" -f -a lookup -d \"Output app information from the App Store\"\ncomplete -c mas -n \"__fish_seen_subcommand_from help\" -xa \"lookup\"\n### lucky\ncomplete -c mas -n \"__fish_use_subcommand\" -f -a lucky -d \"Install the first app returned from searching the App Store\"\ncomplete -c mas -n \"__fish_seen_subcommand_from help\" -xa \"lucky\"\n### open\ncomplete -c mas -n \"__fish_use_subcommand\" -f -a open -d \"Open app page in 'App Store.app'\"\ncomplete -c mas -n \"__fish_seen_subcommand_from help\" -xa \"open\"\n### outdated\ncomplete -c mas -n \"__fish_use_subcommand\" -f -a outdated -d \"List pending app updates from the App Store\"\ncomplete -c mas -n \"__fish_seen_subcommand_from help\" -xa \"outdated\"\ncomplete -c mas -n \"__fish_seen_subcommand_from outdated\" -l verbose -d \"Output warnings about app IDs unknown to the App Store\"\n### reset\ncomplete -c mas -n \"__fish_use_subcommand\" -f -a reset -d \"Reset App Store processes & clear cached App Store downloads\"\ncomplete -c mas -n \"__fish_seen_subcommand_from help\" -xa \"reset\"\ncomplete -c mas -n \"__fish_seen_subcommand_from reset\" -l debug -d \"Output debug information\"\n### search\ncomplete -c mas -n \"__fish_use_subcommand\" -f -a search -d \"Search for apps in the App Store\"\ncomplete -c mas -n \"__fish_seen_subcommand_from help\" -xa \"search\"\ncomplete -c mas -n \"__fish_seen_subcommand_from search\" -l price -d \"Output the price of each app\"\n### seller\ncomplete -c mas -n \"__fish_use_subcommand\" -f -a seller -d \"Open apps' seller pages in the default web browser\"\ncomplete -c mas -n \"__fish_seen_subcommand_from help\" -xa \"seller\"\n### signin\ncomplete -c mas -n \"__fish_use_subcommand\" -f -a signin -d \"Sign in to an Apple Account in the App Store\"\ncomplete -c mas -n \"__fish_seen_subcommand_from help\" -xa \"signin\"\ncomplete -c mas -n \"__fish_seen_subcommand_from signin\" -l dialog -d \"Provide password via graphical dialog\"\n### signout\ncomplete -c mas -n \"__fish_use_subcommand\" -f -a signout -d \"Sign out of the Apple Account currently signed in to the App Store\"\ncomplete -c mas -n \"__fish_seen_subcommand_from help\" -xa \"signout\"\n### uninstall\ncomplete -c mas -n \"__fish_use_subcommand\" -f -a uninstall -d \"Uninstall apps installed from the App Store\"\ncomplete -c mas -n \"__fish_seen_subcommand_from help\" -xa \"uninstall\"\ncomplete -c mas -n \"__fish_seen_subcommand_from uninstall\" -l dry-run -d \"Perform dry run\"\ncomplete -c mas -n \"__fish_seen_subcommand_from uninstall\" -x -a \"(__fish_mas_list_installed)\"\n### update\ncomplete -c mas -n \"__fish_use_subcommand\" -f -a update -d \"Update outdated apps installed from the App Store\"\ncomplete -c mas -n \"__fish_seen_subcommand_from help\" -xa \"update\"\ncomplete -c mas -n \"__fish_seen_subcommand_from update\" -x -a \"(__fish_mas_outdated_installed)\"\n### version\ncomplete -c mas -n \"__fish_use_subcommand\" -f -a version -d \"Output version number\"\ncomplete -c mas -n \"__fish_seen_subcommand_from help\" -xa \"version\"\n"
  }
]