IT業界のすみっこ暮らし

ふと気がついたときの記録

Visual Studio 2017 version 15.7以上のデバッグ設定について

pie001.hatenablog.com

Visual Studioを更新したら、Webサイトのデバッグの際にブラウザを閉じると同時にデバッグが終了する現象が発生したのでそれの対策方法を調べました。

ブラウザを閉じてもデバッグが止まらないようにする

下記項目のチェックを外すことで解決できます。

  • Projects and Solutions > Web Projects > Stop debugger when browser window is closed
  • Debugging > General > Enable JavaScript debugging for ASP.NET (Chrome, Edge and IE)

f:id:papamau:20180601104851p:plain

f:id:papamau:20180601104858p:plain

C#:EPPLUSで数式設定変更&値検索

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using OfficeOpenXml;

namespace EpplusTest
{
    public class Program
    {
        public static void Main(string[] args)
        {
            //ModifiedExcel();
            SelectExcel();
        }

        public static void ModifiedExcel()
        {
            var path = string.Format(@"{0}\テスト.xlsx", TEMP_FOLDER);

            FileInfo file = new FileInfo(path);

            using (var package = new ExcelPackage(file))
            {
                ExcelWorkbook workBook = package.Workbook;
                ExcelWorksheet currentWorksheet = workBook.Worksheets.SingleOrDefault(w => w.Name == "SheetName");

                int totalRows = currentWorksheet.Dimension.End.Row;
                int totalCols = currentWorksheet.Dimension.End.Column;

                // 数式設定
                currentWorksheet.Cells["W5"].Formula = "=IFERROR($S$5*$V5/$U$5,0)";
                currentWorksheet.Cells["W6"].Formula = "=IFERROR($S$6*$V6/$U$6,0)";

                // 数式設定をした後、その値を取得して再利用する場合(=数式設定の値を確定させる)
                // (https://github.com/JanKallman/EPPlus/wiki/Formula-Calculation)

                // 指定セルに数式設定
                currentWorksheet.Cells["AM7"].Formula = "INT(AK7)";
                currentWorksheet.Cells["AM8"].Formula = "INT(AK8)";
                currentWorksheet.Cells["AM9"].Formula = "INT(AK9)";
                currentWorksheet.Cells["AM10"].Formula = "INT(AK10)";
                currentWorksheet.Cells["AM11"].Formula = "INT(AK11)";
                currentWorksheet.Cells["AM12"].Formula = "INT(AK12)";
                currentWorksheet.Cells["AM13"].Formula = "INT(AK13)";

                // ファイル単位、シート単位、セル単位でCalculate()を呼び出して値を確定させる。
                //currentWorksheet.Cells["AM7"].Calculate(); // セル単位でCalculate()
                workBook .Calculate();//ファイル単位でCalculate()
                currentWorksheet.Calculate(); // シート単位でCalculate()
                var amVal = currentWorksheet.Cells["AM8"].Value;
                var amCell = currentWorksheet.Cells["AM8"];
                var aqCell = currentWorksheet.Cells["AQ3"];


                package.Save();
            }
        }

        public static void SelectExcel()
        {
            var path = string.Format(@"{0}\テスト.xlsx", TEMP_FOLDER);

            FileInfo file = new FileInfo(path);

            using (var package = new ExcelPackage(file))
            {
                ExcelWorkbook workBook = package.Workbook;
                ExcelWorksheet currentWorksheet = workBook.Worksheets.SingleOrDefault(w => w.Name == "SheetName");

                int totalRows = currentWorksheet.Dimension.End.Row;
                int totalCols = currentWorksheet.Dimension.End.Column;

                // 指定範囲のセルの中で指定の値を持つセルを抽出
                var query =
                    from cell in currentWorksheet.Cells["H4:H558"]
                    where cell.Value?.ToString() == "例外"
                    select cell;

                // 抽出したセルからセル住所(ex)"H123"を取得して、同じ行の別カラムの値を変更
                foreach(var cell in query)
                {
                    string adr = cell.Address;
                    currentWorksheet.Cells[adr.Replace("H", "W")].Formula = "=iferror($s$1*$v5/$u$1,0)";
                }

                // ## 日付が設定されているセルの扱い方
                var Cell = currentWorksheet.Cells["D5"];
                // 日付形式はvalueからdatetimeに変換
                long dateNum = long.Parse(ahCell.Value.ToString());
                DateTime result = DateTime.FromOADate(dateNum);
                string strResult = result.ToString("yyyy/MM/dd");


                // ## 既存のエクセルファイルの値を変更した後、それを基準に検索して再度値を変更
                currentWorksheet.Cells["H500"].Value = "テスト";

                // package.Save()前の変更内容も検索可能
                var query2 =
                    from cell in currentWorksheet.Cells["H4:H558"]
                    where cell.Value?.ToString() == "テスト"
                    select cell;

                foreach (var cell in query2)
                {
                    string adr = cell.Address;
                    currentWorksheet.Cells[adr.Replace("H", "W")].Formula = "=iferror($s$1111*$v1111/$u$1111,0)";
                }

                package.Save();
            }
        }

        public static string TEMP_FOLDER
        {
            get
            {
                string logFolder = string.Format(@"{0}\{1}", Environment.CurrentDirectory, "Temp");
                if (!Directory.Exists(logFolder)) { Directory.CreateDirectory(logFolder); }
                return logFolder;
            }
        }
    }
}

参考

github.com

jQueryのclickイベントに関してメモ

下記のコードでunbind('click')がない場合、既に$('input[id^=attachmentData]')にclickイベントが宣言されている場合、同じイベントが重複して宣言されてしまう。

$('#elementId').unbind('click').click(function () {
    // 何らかの処理
});

なんでunbind('click')がないとダメか

ダメな例

下記のような初期設定を行うinit関数の中にclickイベントを設定した場合
※SPA開発で一つの画面で詳細画面を切り替えたり、、、

function init(){
    $('#elementId').click(function () {
        // 何らかの処理
        console.log('何らかの処理');
    });
}
1回目の初期設定後(ex) SPAな画面ではじめて詳細画面を開いた)
何らかの処理(clickイベントが1回実行される)
2回目の初期設定後(ex) SPAな画面で2回に詳細画面を開いた)
何らかの処理(1回目に宣言されたclickイベントが実行される)
何らかの処理(2回目に宣言されたclickイベントが実行される)
3回目の初期設定後(ex) SPAな画面で3回に詳細画面を開いた)
何らかの処理(1回目に宣言されたclickイベントが実行される)
何らかの処理(2回目に宣言されたclickイベントが実行される)
何らかの処理(3回目に宣言されたclickイベントが実行される)

これが新しく画面をレンダリングし直すまで永遠に続きます。
当然、正常な処理が出来るはずがないのでこういう作りは駄目です。

もちろん、SPAじゃない作りであれば問題ありません。

正しい例

前提はダメな例と同じです。

function init(){
    $('#elementId').unbind('click').click(function () {
        // 何らかの処理
        console.log('何らかの処理');
    });
}
1回目の初期設定後(ex) SPAな画面ではじめて詳細画面を開いた)
何らかの処理

clickイベントが1回実行される

2回目の初期設定後(ex) SPAな画面で2回に詳細画面を開いた)
何らかの処理

既存のclickイベントは全て無効にされ、2回目に宣言されたイベントのみが実行される

3回目の初期設定後(ex) SPAな画面で3回に詳細画面を開いた)
何らかの処理

既存のclickイベントは全て無効にされ、3回目に宣言されたイベントのみが実行される

Bonfire Frontend #1に参加してきました

f:id:papamau:20180327155600j:plain

イベント概要

ヤフー主催の「フロントエンド」にフォーカスした情報共有を定期的に行う勉強会/交流会イベントです。

様々な最新技術の活用方法やデザイナー、バックエンドとの連携など、フロントエンドが抱える課題を共有し、フロントエンドについてを熱く語る会を目指します!

yj-meetup.connpass.com


参加した経緯

今までフロントエンド&バックエンド全般に関わりながらWeb開発はしてきましたが、フロントエンドはいつもトレンドが変わるし、教えることが多い反面その技術の賞味期限は短い気がして本腰を入れて何かを学ぼうと思ったことはありませんでした。が、「そもそもフロントエンドエンジニアと自称できる人たちはどういう人たちでどういう話をしてるんだろう?」と気になって、イベントに参加することになりました。

余談ですが、今回は申込数も多くて、抽選に当たって大変嬉しかったです。
みんなフロントエンドに興味あるんだな!と思いました。
確かに特定の言語、フレームワークではなく、フロントエンド括りだとそこまで参加したいほどのイベントは少ないかも知れません。
(たくさんあったらごめんなさい…)

イベント内容

※現時点で共有されている資料をリンクしました。

speakerdeck.com

speakerdeck.com

s.aho.mu

感想

フロントエンドを中心にバリバリ働いてる人たちの現在の組織体制&最新技術の取り入れ方&フロントエンドエンジニアの理想論?みたいな話がたくさん聞けて楽しかったです。

みんなに共通することは、フロントエンドをやっているからといってそれだけやってはいけない。ことでしょうか。

専門性は高めつつも幅広い知識と自分の専門じゃないから興味ない~は危ないと改めて思いました。

また、アンテナを立てて常に情報を収集することは大事だが、一人でなんでもかんでも知ってて出来る人は限りがある。まずは長く愛されているメインとなる技術の概念をしっかりと理解しながら、技術革新に備えようということが一番心に残りました。これはフロントエンド、バックエンドに関わらず共通する話だと思います。流行の技術を触っていないとすぐ劣ってしまうのではないかという不安もよく感じるIT業界ですが、焦らずゆっくり進めて行きたいと改めて思いました。

えっと、まずはGo言語でも学ぶべきかな(苦笑

ASP.NET MVCの開発がはじめての人向けのアドバイス

最近、職場でASP.NET MVCを初めて触りながら開発してる人に対し、その人の作ったコードを見ながらコードレビューというより、ASP.NET MVCではこういうことが出来ます。とアドバイスをする機会があったので、その内容を簡単にまとめてみました。

1、アプリケーション設定は環境ごとに分ける

検証環境と本番環境でキーは同じだけど、値は違うものを使いたい場合、以下の内容を追加して環境ごとに値を上書きします。

xdt:Transform="Replace" xdt:Locator="Match(key)" 

【Web.config】環境ごとに異なる値の設定(見本)

Web.config (例) 開発環境)
<appSettings>
    <add key="env" value="Local"/>
</appSettings>
Web.Debug.config (例) 検証環境)
<appSettings>
    <add key="env" value="Test" xdt:Transform="Replace" xdt:Locator="Match(key)" />
</appSettings>
Web.Release.config (例) 本番環境)
<appSettings>
    <add key="env" value="Live" xdt:Transform="Replace" xdt:Locator="Match(key)" />
</appSettings>


2、Log4netの設定

Log4netの設定はWeb.configのConfiguration(Debug/Release)ごとに設定を分けます。

Properties\AssemblyInfo.cs
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: log4net.Config.XmlConfigurator(Watch = true)]★追加
Web.config (例) 開発環境)
<log4net debug="true">
  <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
    <param name="File" value="C:\logs\" />
    <param name="AppendToFile" value="true" />
    <param name="MaxSizeRollBackups" value="10" />
    <param name="RollingStyle" value="date" />
    <param name="StaticLogFileName" value="false" />
    <param name="DatePattern" value='yyyy-MM-dd".log"' />
    <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
    <layout type="log4net.Layout.PatternLayout">
      <param name="ConversionPattern" value="%d [%t] %-5p - %m%n" />
    </layout>
  </appender>
    <root>
      <level value="DEBUG" />
      <appender-ref ref="RollingLogFileAppender" />
    </root>
</log4net>
Web.Debug.config/Web.Release.config ※環境に合わせて設定する
<log4net debug="true" xdt:Transform="Replace">
  <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
    <param name="File" value="C:\logs\Test\" />
    <param name="AppendToFile" value="true" />
    <param name="MaxSizeRollBackups" value="10" />
    <param name="RollingStyle" value="date" />
    <param name="StaticLogFileName" value="false" />
    <param name="DatePattern" value='yyyy-MM-dd".log"' />
    <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
    <layout type="log4net.Layout.PatternLayout">
      <param name="ConversionPattern" value="%d [%t] %-5p - %m%n" />
    </layout>
  </appender>
    <root>
      <level value="DEBUG" />
      <appender-ref ref="RollingLogFileAppender" />
    </root>
</log4net>


3、Action呼出前後の共通ロジックと共通認証

MVCではActionFilterAttributeを継承したカスタムAttributeの中でActionが呼ばれる前後のタイミングで共通処理を行うことができます。

3-1、Action呼出前後の共通ロジックの参考

/Filters/KariiInitAttribute.cs (仮)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace Pj.Kari.Filters
{
    // カスタム アクション フィルターの作成
    // https://msdn.microsoft.com/ja-jp/library/dd381609(v=vs.98).aspx
    public class KariInitAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
        }

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            base.OnActionExecuted(filterContext);
        }
    }
}


KariInitAttribute適用例

※Controller/Action単位で適用されます。

[KariInit]
public class HonyararaController : BaseController


もし特定のController/Actionのときはフィルターの適用をしたくない場合(Controller単位でカスタムAttributeを適用させた場合など)、下記の方法で現在のController/Actionを取得し、対象外にすることも出来ます。

var currentController = httpContext.Request.RequestContext.RouteData.Values["controller"].ToString();
var currentAction = httpContext.Request.RequestContext.RouteData.Values["action"].ToString();


3-2、共通認証の参考

Actionが呼ばれる前に認証をさせる場合(ログインユーザーか、権限を持っているかなどのチェック)はAuthorizeAttributeを継承したカスタムAttributeの使用がおすすめです。適用例は「3-1、Action呼出前後の共通ロジックの参考」と同じです。

参考ページ

asp.net-mvc - MVC 4でのAuthorizeAttributeのオーバーライド asp.net-mvc-3 asp.net-mvc-4 | CODE Q&A [日本語]

MyAuthorizeAttribute
public class MyAuthorizeAttribute: AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var authorized = base.AuthorizeCore(httpContext);
        if (!authorized)
        {
            // The user is not authorized => no need to go any further
            return false;
        }

        // We have an authenticated user, let's get his username
        string authenticatedUser = httpContext.User.Identity.Name;

        // and check if he has completed his profile
        if (!this.IsProfileCompleted(authenticatedUser))
        {
            // we store some key into the current HttpContext so that 
            // the HandleUnauthorizedRequest method would know whether it
            // should redirect to the Login or CompleteProfile page
            httpContext.Items["redirectToCompleteProfile"] = true;
            return false;
        }

        return true;
    }

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Items.Contains("redirectToCompleteProfile"))
        {
            var routeValues = new RouteValueDictionary(new
            {
                controller = "someController",
                action = "someAction",
            });
            filterContext.Result = new RedirectToRouteResult(routeValues);
        }
        else
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
    }

    private bool IsProfileCompleted(string user)
    {
        // You know what to do here => go hit your database to verify if the
        // current user has already completed his profile by checking
        // the corresponding field
        throw new NotImplementedException();
    }
}


4、例外の集約

ASP.NET MVCでは例外を集約して処理可能です。また、ユーザーの動向をその都度ログに出力することも出来ます。

参考ページ

ASP.NET MVCの集約例外処理
https://qiita.com/mocha/items/6928870b2d02d4c1ac37

サンプル

Global.asax.cs
protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);//activeにする★
    RouteConfig.RegisterRoutes(RouteTable.Routes);
}

// Application_Errorを使っている場合はコメントアウトにする
//protected void Application_Error(object sender, EventArgs e)
//{
//    var exception = Server.GetLastError();
//    if (exception == null)
//    {
//        return;
//    }
//    Log.Err(exception.Message, exception);
//}


App_Start/FilterConfig.cs
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    //filters.Add(new HandleErrorAttribute());//MVC Defaultはコメントアウト

    filters.Add(new LogAttribute()); //ユーザーの動向をログ出力
    filters.Add(new ExceptionHandleAttribute()); //集約例外処理
}


Filters/ExceptionHandleAttribute.cs ※新規追加
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace Pj.Kari.Filters
{
    public class ExceptionHandleAttribute : HandleErrorAttribute
    {
        readonly log4net.ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        public override void OnException(ExceptionContext exceptionContext)
        {
            var controllerName = exceptionContext.RouteData.Values["controller"].ToString();
            var actionName = exceptionContext.RouteData.Values["action"].ToString();
            var exceptionMsg = exceptionContext.Exception.Message;
            var exMessage = string.Format("{0}", exceptionMsg);

            // リファレンスエラー
            if (exceptionContext.Exception.GetType() == typeof(NullReferenceException))
            {
                // 
            }

            // 認証エラー
            if (exceptionContext.Exception.GetType() == typeof(HttpAntiForgeryException))
            {
                exceptionContext.ExceptionHandled = true;
                exceptionContext.Result = new RedirectToRouteResult(
                    new RouteValueDictionary(
                        new
                        {
                            controller = "Home",
                            action = "Index"
                        })
                );
                return;
            }

            if (exceptionContext.ExceptionHandled)
            {
                return;
            }

            // Ajaxリクエストエラー
            if (exceptionContext.HttpContext.Request.IsAjaxRequest())
            {
                var text = string.Empty;
                text = HttpUtility.JavaScriptStringEncode(exceptionMsg);

                exceptionContext.Result = new JavaScriptResult()
                {
                    // jsを返すことが可能
                    //Script = "alert('エラーが発生しました。');"
                };
            }
            else
            {
                exceptionContext.Result = new ViewResult()
                {
                    ViewName = "../Error/Error", // ★表示したい共通のエラー画面
                    ViewData = new ViewDataDictionary
                    {
                        Model = new HandleErrorInfo(exceptionContext.Exception, controllerName, actionName)
                    }
                };
            }

            var errorMsgList = new List<string>();
            var innerExection = exceptionContext.Exception;
            while (innerExection != null)
            {
                errorMsgList.Add(innerExection.Message);
                innerExection = innerExection.InnerException;
            }

            logger.Fatal(string.Format("{1}{0}{2}", Environment.NewLine, exMessage, string.Join(Environment.NewLine, errorMsgList)), exceptionContext.Exception);
            exceptionContext.ExceptionHandled = true;
            exceptionContext.HttpContext.Response.StatusCode = 500;
            HttpContext.Current.Response.TrySkipIisCustomErrors = true;
        }
    }
}


Filters/LogAttribute.cs ※新規追加
using log4net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Security.Claims;
using System.Web;
using System.Web.Mvc;

namespace Pj.Kari.Filters
{
    public class LogAttribute : ActionFilterAttribute
    {
        private ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        private Stopwatch stopwatch = new Stopwatch();

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            stopwatch.Reset();
            stopwatch.Start();

            // ユーザー情報を取得して、現在あるユーザーがどのような操作をしているかをログに記録することができる
            log.Debug(string.Format("▼Start...{0}.{1}",
                // ユーザーID
                // ユーザー名
                filterContext.RouteData.Values["controller"],
                filterContext.RouteData.Values["action"]));
        }

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            //filterContext.Exception

            // レスポンスヘッダーにキャッシュ無効化を追加
            var response = filterContext.HttpContext.Response;
            response.Cache.SetCacheability(HttpCacheability.NoCache);

            base.OnActionExecuted(filterContext);
        }

        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            base.OnResultExecuting(filterContext);
        }

        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            // ユーザー情報を取得して、現在あるユーザーがどのような操作をしているかをログに記録することができる
            stopwatch.Stop();
            log.Debug(string.Format("▲End.....{0}.{1}..........took {2}ms",
                // ユーザーID
                // ユーザー名
                filterContext.RouteData.Values["controller"],
                filterContext.RouteData.Values["action"],
                stopwatch.ElapsedMilliseconds));
        }
    }
}


 5、セキュリティ対策

下記記事の内容と同様。 pie001.hatenablog.com


以上

Macでrubyのバージョンアップ手順

1、brew update

# brew update
$ brew update

permission系のエラーが出る場合は該当パスへ移動する

$ cd /Library/Developer/CommandLineTools

結果として下記のように表示されたらOK

Already up-to-date.


2、brew install

# brew install
$ brew install rbenv ruby-build


下記のようなエラーが出た場合はX-codeをインストールする

==> Installing dependencies for rbenv: autoconf, pkg-config, openssl, ruby-build
==> Installing rbenv dependency: autoconf
xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
Error: Failure while executing: git config --local --replace-all homebrew.private true
# X-codeインストール
$ sudo xcode-select --install


3、最新バージョンのrubyをインストール

# バージョン一覧を確認
$ rbenv install --list
  2.4.3
  2.5.0-dev
  2.5.0-preview1
  2.5.0-rc1
  2.5.0
  2.6.0-dev
  2.6.0-preview1


現在確認できるバージョンでは2.5.0が一番最新の安定版みたいなので(?)2.5.0を入れる

#rubyの最新バージョンをインストール
$ rbenv install 2.5.0


4、バージョンが反映されない場合

# rubyのバージョン確認
$ ruby -v
ruby 2.3.3p222 (2016-11-21 revision 56859) [universal.x86_64-darwin17]

rubyのバージョンを確認するとmacのデフォルトバージョンのままである。
じゃrbenvのバージョンは?…ちゃんと2.5.0が表示される

# rbenvのバージョン確認
$ rbenv versions
  system
* 2.5.0 (set by /Users/yjpark/.rbenv/version)


witch rubyで結果が以下の場合はPATH設定が足りないのが原因

$ witch ruby
/usr/bin/ruby


解決方法は~/.bash_profileに[eval "$(rbenv init -)"](rbenv initのPATH設定)を追加する

$ rbenv init
eval "$(rbenv init -)" #この内容をコピして~/.bash_profileに追記


~/.bash_profileの内容を修正する

$ vim ~/.bash_profile
$ source ~/.bash_profile


再度、rubyのバージョンを確認する。2.5.0が確認できる。

$ ruby -v
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-darwin17]


which rubyも確認してみる。

$ which ruby
/Users/{user_id}/.rbenv/shims/ruby


これで完了


参考

rbenvでmacのrubyを最新にする - Qiita

rbenvでバージョンがうまく切り替わらなかった時にやったこと - Qiita

Chromeに入れてる拡張機能

Full Page Screen Capture

全体画面のキャプチャにはこれは一番機能がシンプルで気に入ってる

chrome.google.com

AdBlock

chrome.google.com

Ginger

英語のスペルチェックにとても便利

Ginger Software | English Grammar & Writing App

chrome.google.com

Wappalyzer

気になるWebサイトの技術を確認できる

chrome.google.com

ブクマ20180306

VPSで試してから触りたいクラウドサービスを検討中

heroku

www.heroku.com

www.sejuku.net

blog.ruedap.com

GAE

cloud.google.com

azure

Azure の無料アカウントを今すぐ作成しましょう | Microsoft Azure

AWS

aws.amazon.com

aws.amazon.com

qiita.com

UI参考

coliss.com

さくらVPSを申し込みました

言語はなんでもいいから簡単なサービスを作ってみようーと思って一番手軽?そうなさくらVPSに手を出して見ました。

申し込み仕様

  • サービス:さくらのVPS(v4) SSD 1G TK02
  • リージョン: 東京 第2ゾーン
  • お申し込み数: 1

これからこれ↓見ながらセッティングしますー

【さくらのVPS】サーバの初期設定ガイド – さくらのサポート情報

参考予定

さくらのVPSにMACのターミナルからSSH接続する方法 | さくらインターネットのVPS設定マニュアル

さくらVPSをmacのターミナルから接続する際にSSH接続ができない時の対処法 - Cebudepiiiya

インフラエンジニアじゃなくても押さえておきたいSSHの基礎知識 - Qiita

さくらのVPS Mac OS Xのターミナルからログインする方法 - AkicanBlog

追記 (2018.03.11)

お試し期間中にある程度触ってみたけど、やはりまだ動くものができてないとちょっとお金がもったいないということで申し込みはキャンセルしました。後日サービスを公開するときには再申込したいと思います。