LoginSignup
21
21

More than 5 years have passed since last update.

Mac OSX での開発環境構築

Last updated at Posted at 2014-07-19

このページの情報は既に古くなっています。
このページの通りには構築を行えません。

このメモは、Mac ( OS X 10.9.4 ) を使用したメモです。

Command Line Tools をインストールする

Xcode を Apple Store からダウンロードしてインストール。
インストール後、下記コマンドを実行する。

$ xcode-select --install

パッケージマネージャーをインストールする

Homebrew のインストール

おおもとのパッケージマネージャーには Homebrew 使用します。

$ ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"

PATH を通す

$ sudo mkdir /usr/local/sbin

/Users/YOUR USERNAME/.bash_profile ファイルを編集

.bash_profile
export PATH=/usr/local/bin:$PATH
export PATH=/usr/local/sbin:$PATH

正常にインストールされているかチェック

$ brew doctor

Your system is ready to brew.

と表示されれば大丈夫。もし、エラーが発生した場合、以下を参考にしてみてる。

パッケージのアップデート

$ brew update
$ brew doctor

もし、エラーが発生した場合、以下を参考にしてみてる。
* brew updateのエラー回避

必要なパッケージをインストール

以下は適当に並べているので、必要なものを必要なだけ適宜追加。

$ brew install wget
$ brew install node
$ brew install mysql

Gulp と bower をインストール

Gulp と node.js のパッケージマネージャー npm がインストール済である事が条件。
* Gulp : JSのタスクランナー
* Bower: Twitterが出しているフロントエンド用のパッケージマネージャー

インストール

$ npm install –g gulp bower

各パッケージのアップデート

$ npm update -g bower

rbenv を利用した Ruby 環境の構築

rbenv を利用する事で、OS X 上で複数バージョンの Ruby を切り替えて使用する事ができる。

rbenv と ruby-build のインストール

以下のコマンドを実行してインストールする。

$ brew install rbenv ruby-build

PATH を通す

インストールが完了したら、rbenv の PATH を通す為に .bash_profile ファイルを編集。
Homebrew インストールと合わせて以下のようになる。

.bash_profile
export PATH=/usr/local/bin:$PATH
export PATH=/usr/local/sbin:$PATH
export PATH=$HOME/.rbenv/bin:$PATH
eval "$(rbenv init -)"

Ruby をインストール

インストール可能な Ruby のバージョンを確認

$ rbenv install -l
Available versions:
  1.8.6-p383
  1.8.6-p420
  1.8.7-p249
  1.8.7-p302
  1.8.7-p334
  1.8.7-p352
  1.8.7-p357
  1.8.7-p358
  1.8.7-p370
  1.8.7-p371
  1.8.7-p374
  1.8.7-p375
  1.9.1-p378
  1.9.1-p430
  1.9.2-p0
  1.9.2-p180
  1.9.2-p290
  1.9.2-p318
  1.9.2-p320
  1.9.2-p326
  1.9.3-dev
  1.9.3-p0
  1.9.3-p125
  1.9.3-p194
  1.9.3-p286
  1.9.3-p327
  1.9.3-p362
  1.9.3-p374
  1.9.3-p385
  1.9.3-p392
  1.9.3-p429
  1.9.3-p448
  1.9.3-p484
  1.9.3-p545
  1.9.3-p547
  1.9.3-preview1
  1.9.3-rc1
  2.0.0-dev
  2.0.0-p0
  2.0.0-p195
  2.0.0-p247
  2.0.0-p353
  2.0.0-p451
  2.0.0-p481
  2.0.0-preview1
  2.0.0-preview2
  2.0.0-rc1
  2.0.0-rc2
  2.1.0
  2.1.0-dev
  2.1.0-preview1
  2.1.0-preview2
  2.1.0-rc1
  2.1.1
  2.1.2
  2.2.0-dev

任意のバージョンをインストール

$ rbenv install 2.1.2

Ruby のバージョンを切り替える

$ rbenv global 2.1.2

現在の Ruby のバージョンを確認する

$ rbenv versions
  system
* 2.1.2 (set by /Users/YOUR USERNAME/.rbenv/version)

phpenv を利用した PHP 環境の構築

phpenv を利用する事で、OS X 上で複数バージョンの PHP を切り替えて使用する事ができる。

phpenv のインストール

以下のコマンドを実行してインストールする。
なお、php-build も必要だが、ここではインストールしない。

$ brew install phpenv

php-build のインストール

インストールが完了したら、php-build を phpenv のプラグインとしてインストールする。

$ git clone git@github.com:CHH/php-build.git ~/.phpenv/plugins/php-build

PATH を通す

インストールが完了したら、rbenv の PATH を通す為に .bash_profile ファイルを編集。
Homebrew と rbenv のインストールと合わせて以下のようになる。

.bash_profile
export PATH=/usr/local/bin:$PATH
export PATH=/usr/local/sbin:$PATH
export PATH=$HOME/.rbenv/bin:$HOME/.phpenv/bin:$PATH
eval "$(rbenv init -)"
eval "$(phpenv init -)"

PHP をインストール

インストール可能な PHP のバージョンを確認

$ phpenv install -l
usage: phpenv install VERSION
       phpenv install /path/to/definition

Available versions:
  5.2.17
  5.3.10
  5.3.11
  5.3.11RC1
  5.3.11RC2
  5.3.12
  5.3.13
  5.3.14
  5.3.15
  5.3.16
  5.3.17
  5.3.18
  5.3.19
  5.3.19RC1
  5.3.2
  5.3.20
  5.3.20RC1
  5.3.21
  5.3.22
  5.3.23
  5.3.24
  5.3.25
  5.3.26
  5.3.27
  5.3.28
  5.3.3
  5.3.6
  5.3.8
  5.3.9
  5.3.9RC3
  5.3.9RC4
  5.3snapshot
  5.4.0
  5.4.0RC1
  5.4.0RC2
  5.4.0RC3
  5.4.0RC4
  5.4.0RC5
  5.4.0RC6
  5.4.0RC7
  5.4.0RC8
  5.4.0alpha3
  5.4.0beta1
  5.4.0beta2
  5.4.1
  5.4.10
  5.4.10RC1
  5.4.11
  5.4.12
  5.4.13
  5.4.14
  5.4.15
  5.4.16
  5.4.17
  5.4.18
  5.4.19
  5.4.1RC1
  5.4.1RC2
  5.4.2
  5.4.20
  5.4.21
  5.4.22
  5.4.23
  5.4.24
  5.4.25
  5.4.26
  5.4.27
  5.4.28
  5.4.3
  5.4.4
  5.4.5
  5.4.6
  5.4.7
  5.4.8
  5.4.9
  5.4.9RC1
  5.4snapshot
  5.5.0
  5.5.0RC1
  5.5.0RC2
  5.5.0RC3
  5.5.0alpha1
  5.5.0alpha2
  5.5.0alpha3
  5.5.0alpha4
  5.5.0alpha5
  5.5.0alpha6
  5.5.0beta1
  5.5.0beta2
  5.5.0beta3
  5.5.0beta4
  5.5.1
  5.5.10
  5.5.11
  5.5.12
  5.5.2
  5.5.3
  5.5.4
  5.5.5
  5.5.6
  5.5.7
  5.5.8
  5.5.9
  5.5snapshot
  5.6.0alpha1
  5.6.0alpha2
  5.6.0alpha3
  5.6.0beta1
  5.6.0beta2
  5.6snapshot
  master

任意のバージョンをインストール

$ phpenv install 5.4.9
エラーがでたら その1
-----------------
|  BUILD ERROR  |
-----------------

Here are the last 10 lines from the log:

-----------------------------------------
  "_sk_shift", referenced from:
      _load_all_certs_from_file in openssl.o
  "_sk_value", referenced from:
      _zif_openssl_csr_new in openssl.o
      _zif_openssl_pkcs7_verify in openssl.o
      _php_openssl_parse_config in openssl.o
      _php_openssl_sockop_set_option in xp_ssl.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [libs/libphp5.bundle] Error 1
-----------------------------------------

このようなエラーがでた場合、OpenSSLのバージョンアップを行う。

PHPのインストールでコンパイルエラーが発生する on Mac OSX

$ brew install openssl
$ brew link openssl --force
$ exec $SHELL -l

PHP のバージョンを切り替える

$ phpenv global 5.4.9

現在の PHP のバージョンを確認する

$ phpenv versions
  system
* 5.4.9 (set by /Users/YOUR USERNAME/.phpenv/version)

WP-CLI をインストール

$ brew install composer --ignore-dependencies
$ brew install wp-cli --ignore-dependencies

フロントエンドの各種ツールをインストール

Gulp

Gulp と bower をインストールを済ませておく。
もっと効率がよい書き方のアドバイスお待ちしています(・∀・)

gulpfile

gulpfile.js
"use strict";

var gulp        = require('gulp'),
    $           = require('gulp-load-plugins')(),
    cmq         = require('gulp-combine-media-queries'),
    browserSync = require('browser-sync'),
    reload      = browserSync.reload,
    sources     = {
        scss:         'assets/scss/**/*.scss',
        scssDir:      'assets/scss/',
        scssBuildDir: 'assets/scss/_build/',
        css:          'assets/scss/_build/**/*.css',
        cssDir:       'assets/css/',
        js:           'assets/js/src/**/*.js',
        jsDir:        'assets/js/',
        jsSrcDir:     'assets/js/src/',
        jsDestDir:    'assets/js/dist/',
        jsArray:      [
                        'assets/js/src/foundation.js',
                        'assets/js/src/foundation.topbar.js',
                        'assets/js/src/jquery.viewportchecker.js',
                        'assets/js/src/jquery.stellar.js',
                        'assets/js/src/highlight.js',
                        'assets/js/src/jquery.unveil.js',
                        'assets/js/src/jquery.cherryblossom.js'
                      ],
    };

// ===== StyleDocco ===== //
// gulp.task('styledocco', function() {
//     return gulp.src(sources.css)
//         .pipe($.plumber())
//         .pipe($.styledocco({
//           out:  '_docs',
//           name: 'StyleGuide'
//         }));
// });
// ===== StyleDocco ===== //

// ===== Scss build ===== //
gulp.task('scss', function(){
    gulp.src(sources.scss)
       .pipe($.plumber())
       .pipe($.compass({
           config_file: 'config.rb',
           comments:     false,
           css:          sources.scssBuildDir,
           sass:         sources.scssDir
       }));
});
// ===== Scss build ===== //

// ===== Css optimaize ===== //
gulp.task('css', function(){
    gulp.src(sources.css)
       .pipe($.plumber())
       .pipe($.autoprefixer('last 2 version', 'ie 8', 'ios 6', 'android 2.3'))
       .pipe($.csscomb('csscomb.json'))
       .pipe(cmq())
       .pipe(gulp.dest(sources.cssDir))
       .pipe($.rename({suffix: '.min'}))
       .pipe($.csso())
       .pipe(gulp.dest(sources.cssDir));
});
// ===== Css optimaize ===== //

// ===== JS optimaize ===== //
gulp.task('js', function(){
    gulp.src(sources.jsArray)
       .pipe($.plumber())
       .pipe($.concat('script.js'))
       .pipe(gulp.dest(sources.jsDestDir))
       .pipe($.rename({suffix: '.min'}))
       .pipe($.uglify({preserveComments: 'some'}))
       .pipe(gulp.dest(sources.jsDestDir));
});
// ===== JS optimaize ===== //

// ===== Watch ===== //
gulp.task('watch', function(){
    gulp.watch([sources.scss], ['scss']);
    gulp.watch([sources.css], ['css']);
    gulp.watch([sources.js], ['js']);
});
// ===== Watch ===== //

// ===== Default task ===== //
gulp.task('default', ['scss', 'css', 'js'], function(){
    // browserSync.init(null, {
    //     proxy: 'kuck1u.local'
    // });

    gulp.run('watch');
});
// ===== Default task ===== //

package.json

package.json
{
  "devDependencies": {
    "browser-sync": "^1.8.3",
    "gulp": "^3.8.10",
    "gulp-autoprefixer": "^2.0.0",
    "gulp-combine-media-queries": "^0.2.0",
    "gulp-compass": "^2.0.3",
    "gulp-concat": "^2.4.3",
    "gulp-csscomb": "^3.0.3",
    "gulp-csso": "^0.2.9",
    "gulp-load-plugins": "^0.8.0",
    "gulp-plumber": "^0.6.6",
    "gulp-rename": "^1.2.0",
    "gulp-uglify": "^1.0.2"
  }
}

csscomb.json

csscomb.json
{
    "exclude": [
        ".git/**",
        "node_modules/**",
        "bower_components/**"
    ],
    "always-semicolon": true,
    "block-indent": "    ",
    "color-case": "lower",
    "color-shorthand": true,
    "element-case": "lower",
    "eof-newline": true,
    "leading-zero": false,
    "quotes": "single",
    "remove-empty-rulesets": true,
    "space-after-colon": " ",
    "space-after-combinator": " ",
    "space-after-opening-brace": "\n",
    "space-after-selector-delimiter": "\n",
    "space-before-closing-brace": "\n",
    "space-before-colon": "",
    "space-before-combinator": " ",
    "space-before-opening-brace": " ",
    "space-before-selector-delimiter": "",
    "strip-spaces": true,
    "unitless-zero": true,
    "vendor-prefix-align": true,
    "sort-order": [
        [
            "font",
            "font-family",
            "font-size",
            "font-weight",
            "font-style",
            "font-variant",
            "font-size-adjust",
            "font-stretch",
            "font-effect",
            "font-emphasize",
            "font-emphasize-position",
            "font-emphasize-style",
            "font-smooth",
            "line-height",
            "position",
            "z-index",
            "top",
            "right",
            "bottom",
            "left",
            "display",
            "visibility",
            "float",
            "clear",
            "overflow",
            "overflow-x",
            "overflow-y",
            "-ms-overflow-x",
            "-ms-overflow-y",
            "clip",
            "zoom",
            "flex-direction",
            "flex-order",
            "flex-pack",
            "flex-align",
            "-webkit-box-sizing",
            "-moz-box-sizing",
            "box-sizing",
            "width",
            "min-width",
            "max-width",
            "height",
            "min-height",
            "max-height",
            "margin",
            "margin-top",
            "margin-right",
            "margin-bottom",
            "margin-left",
            "padding",
            "padding-top",
            "padding-right",
            "padding-bottom",
            "padding-left",
            "table-layout",
            "empty-cells",
            "caption-side",
            "border-spacing",
            "border-collapse",
            "list-style",
            "list-style-position",
            "list-style-type",
            "list-style-image",
            "content",
            "quotes",
            "counter-reset",
            "counter-increment",
            "resize",
            "cursor",
            "-webkit-user-select",
            "-moz-user-select",
            "-ms-user-select",
            "user-select",
            "nav-index",
            "nav-up",
            "nav-right",
            "nav-down",
            "nav-left",
            "-webkit-transition",
            "-moz-transition",
            "-ms-transition",
            "-o-transition",
            "transition",
            "-webkit-transition-delay",
            "-moz-transition-delay",
            "-ms-transition-delay",
            "-o-transition-delay",
            "transition-delay",
            "-webkit-transition-timing-function",
            "-moz-transition-timing-function",
            "-ms-transition-timing-function",
            "-o-transition-timing-function",
            "transition-timing-function",
            "-webkit-transition-duration",
            "-moz-transition-duration",
            "-ms-transition-duration",
            "-o-transition-duration",
            "transition-duration",
            "-webkit-transition-property",
            "-moz-transition-property",
            "-ms-transition-property",
            "-o-transition-property",
            "transition-property",
            "-webkit-transform",
            "-moz-transform",
            "-ms-transform",
            "-o-transform",
            "transform",
            "-webkit-transform-origin",
            "-moz-transform-origin",
            "-ms-transform-origin",
            "-o-transform-origin",
            "transform-origin",
            "-webkit-animation",
            "-moz-animation",
            "-ms-animation",
            "-o-animation",
            "animation",
            "-webkit-animation-name",
            "-moz-animation-name",
            "-ms-animation-name",
            "-o-animation-name",
            "animation-name",
            "-webkit-animation-duration",
            "-moz-animation-duration",
            "-ms-animation-duration",
            "-o-animation-duration",
            "animation-duration",
            "-webkit-animation-play-state",
            "-moz-animation-play-state",
            "-ms-animation-play-state",
            "-o-animation-play-state",
            "animation-play-state",
            "-webkit-animation-timing-function",
            "-moz-animation-timing-function",
            "-ms-animation-timing-function",
            "-o-animation-timing-function",
            "animation-timing-function",
            "-webkit-animation-delay",
            "-moz-animation-delay",
            "-ms-animation-delay",
            "-o-animation-delay",
            "animation-delay",
            "-webkit-animation-iteration-count",
            "-moz-animation-iteration-count",
            "-ms-animation-iteration-count",
            "-o-animation-iteration-count",
            "animation-iteration-count",
            "-webkit-animation-direction",
            "-moz-animation-direction",
            "-ms-animation-direction",
            "-o-animation-direction",
            "animation-direction",
            "text-align",
            "-webkit-text-align-last",
            "-moz-text-align-last",
            "-ms-text-align-last",
            "text-align-last",
            "vertical-align",
            "white-space",
            "text-decoration",
            "text-emphasis",
            "text-emphasis-color",
            "text-emphasis-style",
            "text-emphasis-position",
            "text-indent",
            "-ms-text-justify",
            "text-justify",
            "letter-spacing",
            "word-spacing",
            "-ms-writing-mode",
            "text-outline",
            "text-transform",
            "text-wrap",
            "text-overflow",
            "-ms-text-overflow",
            "text-overflow-ellipsis",
            "text-overflow-mode",
            "-ms-word-wrap",
            "word-wrap",
            "word-break",
            "-ms-word-break",
            "-moz-tab-size",
            "-o-tab-size",
            "tab-size",
            "-webkit-hyphens",
            "-moz-hyphens",
            "hyphens",
            "pointer-events",
            "opacity",
            "filter:progid:DXImageTransform.Microsoft.Alpha(Opacity",
            "-ms-filter:\\'progid:DXImageTransform.Microsoft.Alpha",
            "-ms-interpolation-mode",
            "color",
            "border",
            "border-width",
            "border-style",
            "border-color",
            "border-top",
            "border-top-width",
            "border-top-style",
            "border-top-color",
            "border-right",
            "border-right-width",
            "border-right-style",
            "border-right-color",
            "border-bottom",
            "border-bottom-width",
            "border-bottom-style",
            "border-bottom-color",
            "border-left",
            "border-left-width",
            "border-left-style",
            "border-left-color",
            "-webkit-border-radius",
            "-moz-border-radius",
            "border-radius",
            "-webkit-border-top-left-radius",
            "-moz-border-radius-topleft",
            "border-top-left-radius",
            "-webkit-border-top-right-radius",
            "-moz-border-radius-topright",
            "border-top-right-radius",
            "-webkit-border-bottom-right-radius",
            "-moz-border-radius-bottomright",
            "border-bottom-right-radius",
            "-webkit-border-bottom-left-radius",
            "-moz-border-radius-bottomleft",
            "border-bottom-left-radius",
            "-webkit-border-image",
            "-moz-border-image",
            "-o-border-image",
            "border-image",
            "-webkit-border-image-source",
            "-moz-border-image-source",
            "-o-border-image-source",
            "border-image-source",
            "-webkit-border-image-slice",
            "-moz-border-image-slice",
            "-o-border-image-slice",
            "border-image-slice",
            "-webkit-border-image-width",
            "-moz-border-image-width",
            "-o-border-image-width",
            "border-image-width",
            "-webkit-border-image-outset",
            "-moz-border-image-outset",
            "-o-border-image-outset",
            "border-image-outset",
            "-webkit-border-image-repeat",
            "-moz-border-image-repeat",
            "-o-border-image-repeat",
            "border-image-repeat",
            "outline",
            "outline-width",
            "outline-style",
            "outline-color",
            "outline-offset",
            "background",
            "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader",
            "background-color",
            "background-image",
            "background-repeat",
            "background-attachment",
            "background-position",
            "background-position-x",
            "-ms-background-position-x",
            "background-position-y",
            "-ms-background-position-y",
            "-webkit-background-clip",
            "-moz-background-clip",
            "background-clip",
            "background-origin",
            "-webkit-background-size",
            "-moz-background-size",
            "-o-background-size",
            "background-size",
            "box-decoration-break",
            "-webkit-box-shadow",
            "-moz-box-shadow",
            "box-shadow",
            "filter:progid:DXImageTransform.Microsoft.gradient",
            "-ms-filter:\\'progid:DXImageTransform.Microsoft.gradient",
            "text-shadow"
        ]
    ]
}

Sass と Compass

インストール

$ sudo gem install compass
$ sudo gem install sass

設定ファイル

config.rb
Encoding.default_external = "utf-8"
# Require any additional compass plugins here.
add_import_path "libs/foundation/bower_components/foundation/scss"

# Set this to the root of your project when deployed:
http_path = "./"
css_dir = "assets/css"
sass_dir = "assets/scss"
images_dir = "assets/imgs"
generated_images_dir = "assets/img/sprite"
http_images_path = "../img"
http_generated_images_dir = "../img/sprite"
javascripts_dir = "assets/js"

# You can select your preferred output style here (can be overridden via the command line):
# output_style = :expanded or :nested or :compact or :compressed
output_style = :expanded

# To enable relative paths to assets via compass helper functions. Uncomment:
# relative_assets = true

# To disable debugging comments that display the original location of your selectors. Uncomment:
line_comments = false

cache = true
asset_cache_buster :none
sass_options = { :debug_info => false }

# If you prefer the indented syntax, you might want to regenerate this
# project again passing --syntax sass, or you can uncomment this:
# preferred_syntax = :sass
# and then run:
# sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass

# キャッシュバスターをタイムスタンプからMD5ハッシュ(10文字)に変更する
asset_cache_buster do |path, file|
  if File.file?(file.path)
    Digest::MD5.hexdigest(File.read(file.path))[0, 10]
  else
    $stderr.puts "WARNING: '#{File.basename(path)}' was not found (or cannot be read) in #{File.dirname(file.path)}"
  end
end

# スプライト画像生成時に生成されたファイル名に自動的に付けられるハッシュ文字列を削除する
on_sprite_saved do |filename|
  if File.file?(filename)
    FileUtils.mv filename, filename.gsub(%r{-s[0-9a-f]{10}(\.\w+)}, '\1')
  end
end

# スプライト画像生成時に生成されたファイル名に自動的に付けられるハッシュ文字列を削除し、
# キャッシュバスターとして利用する
# device-pixel-ratioの分数内に挿入される半角スペースを削除
on_stylesheet_saved do |filename|
  if File.file?(filename)
    css = File.read(filename)
    File.open(filename, 'w+') do |f|
      # f << css.gsub(%r{-s([0-9a-f]{10})(\.\w+)}, '\2?\1').gsub(%r{(device-aspect-ratio:\s*)(\d+)\s*(/)\s*(\d+)}, '\1\2\3\4')
      f << css.gsub(%r{-s([0-9a-f]{10})(\.\w+)}, '\2').gsub(%r{(device-aspect-ratio:\s*)(\d+)\s*(/)\s*(\d+)}, '\1\2\3\4')
    end
  end
end

# require 'autoprefixer-rails'
# require 'csso'
# on_stylesheet_saved do |file|
#   css = File.read(file)
#   File.open(file, 'w') do |io|
#     # io << AutoprefixerRails.compile(css, ['last 3 versions', 'ie 8', 'ios 6', 'android 2.3'])
#     io << AutoprefixerRails.process(css, browsers:['last 3 versions', 'ie 8', 'ios 6', 'android 2.3'])
#     # io << AutoprefixerRails.process(css)
#     # io << Csso.optimize( AutoprefixerRails.process(css, browsers:['last 1 version', 'ie 8', 'ios 6', 'android 2.3']) )
#   end
# end

SSH 公開鍵と秘密鍵の生成

コマンド内にある「github」の部分は適当に変更

# 秘密鍵を生成
$ openssl genrsa -des3 -out ~/.ssh/github_rsa 2048
# パーミッションの変更
$ chmod 600 ~/.ssh/github_rsa
# 公開鍵を生成
$ ssh-keygen -y -f ~/.ssh/github_rsa > ~/.ssh/github_rsa.pub
# 鍵を登録する
$ ssh-add -K ~/.ssh/github_rsa
# 公開鍵をクリップボードにコピー
$ pbcopy < ~/.ssh/github_rsa.pub
21
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
21