関数のソースコードを表示するにはどうすればよいですか?

583
Joshua Ulrich 2013-10-08 03:58.

関数のソースコードを見て、どのように機能するかを確認したいと思います。プロンプトで名前を入力することで関数を印刷できることを知っています。

> t
function (x) 
UseMethod("t")
<bytecode: 0x2332948>
<environment: namespace:base>

この場合、どういうUseMethod("t")意味ですか?たとえば、実際に使用されているソースコードを見つけるにはどうすればよいt(1:10)ですか?

私が見たときとの間に差があるUseMethodと、私が見たときstandardGenericshowMethods場合と同様に、with

> with
standardGeneric for "with" defined from package "base"

function (data, expr, ...) 
standardGeneric("with")
<bytecode: 0x102fb3fc0>
<environment: 0x102fab988>
Methods may be defined for arguments: data
Use  showMethods("with")  for currently available ones.

その他の場合、R関数が呼び出されていることはわかりますが、それらの関数のソースコードが見つかりません。

> ts.union
function (..., dframe = FALSE) 
.cbind.ts(list(...), .makeNamesTs(...), dframe = dframe, union = TRUE)
<bytecode: 0x36fbf88>
<environment: namespace:stats>
> .cbindts
Error: object '.cbindts' not found
> .makeNamesTs
Error: object '.makeNamesTs' not found

.cbindtsおよびのような関数を見つけるにはどうすればよい.makeNamesTsですか?

さらに他のケースでは、Rコードが少しありますが、ほとんどの作業は別の場所で行われているようです。

> matrix
function (data = NA, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL) 
{
    if (is.object(data) || !is.atomic(data)) 
        data <- as.vector(data)
    .Internal(matrix(data, nrow, ncol, byrow, dimnames, missing(nrow), 
        missing(ncol)))
}
<bytecode: 0x134bd10>
<environment: namespace:base>
> .Internal
function (call)  .Primitive(".Internal")
> .Primitive
function (name)  .Primitive(".Primitive")

.Primitive関数が何をするのかを知るにはどうすればよいですか?同様に、一部の機能が呼び出す.C.Call.Fortran.External、または.Internal。それらのソースコードを見つけるにはどうすればよいですか?

10 answers

534
Joshua Ulrich 2013-10-08 03:58.

UseMethod("t")は、さまざまなオブジェクトクラスのメソッドを持つt()S3)ジェネリック関数であることを示しています。

S3メソッドディスパッチシステム

S3クラスの場合、methods関数を使用して、特定の汎用関数またはクラスのメソッドを一覧表示できます。

> methods(t)
[1] t.data.frame t.default    t.ts*       

   Non-visible functions are asterisked
> methods(class="ts")
 [1] aggregate.ts     as.data.frame.ts cbind.ts*        cycle.ts*       
 [5] diffinv.ts*      diff.ts          kernapply.ts*    lines.ts        
 [9] monthplot.ts*    na.omit.ts*      Ops.ts*          plot.ts         
[13] print.ts         time.ts*         [<-.ts*          [.ts*           
[17] t.ts*            window<-.ts*     window.ts*      

   Non-visible functions are asterisked

「非表示の関数にはアスタリスクが付いています」とは、関数がパッケージの名前空間からエクスポートされていないことを意味します。:::関数(ie stats:::t.ts)を使用するか、を使用して、ソースコードを表示できgetAnywhere()ます。 getAnywhere()関数がどのパッケージから来たのかを知る必要がないので便利です。

> getAnywhere(t.ts)
A single object matching ‘t.ts’ was found
It was found in the following places
  registered S3 method for t from namespace stats
  namespace:stats
with value

function (x) 
{
    cl <- oldClass(x)
    other <- !(cl %in% c("ts", "mts"))
    class(x) <- if (any(other)) 
        cl[other]
    attr(x, "tsp") <- NULL
    t(x)
}
<bytecode: 0x294e410>
<environment: namespace:stats>

S4方式ディスパッチシステム

S4システムは、新しいメソッドディスパッチシステムであり、S3システムの代替です。S4関数の例を次に示します。

> library(Matrix)
Loading required package: lattice
> chol2inv
standardGeneric for "chol2inv" defined from package "base"

function (x, ...) 
standardGeneric("chol2inv")
<bytecode: 0x000000000eafd790>
<environment: 0x000000000eb06f10>
Methods may be defined for arguments: x
Use  showMethods("chol2inv")  for currently available ones.

出力はすでに多くの情報を提供しています。standardGenericS4機能の指標です。定義されたS4メソッドを表示するメソッドが役立ちます。

> showMethods(chol2inv)
Function: chol2inv (package base)
x="ANY"
x="CHMfactor"
x="denseMatrix"
x="diagonalMatrix"
x="dtrMatrix"
x="sparseMatrix"

getMethod 次のいずれかの方法のソースコードを確認するために使用できます。

> getMethod("chol2inv", "diagonalMatrix")
Method Definition:

function (x, ...) 
{
    chk.s(...)
    tcrossprod(solve(x))
}
<bytecode: 0x000000000ea2cc70>
<environment: namespace:Matrix>

Signatures:
        x               
target  "diagonalMatrix"
defined "diagonalMatrix"

たとえば、メソッドごとにさらに複雑なシグネチャを持つメソッドもあります。

require(raster)
showMethods(extract)
Function: extract (package raster)
x="Raster", y="data.frame"
x="Raster", y="Extent"
x="Raster", y="matrix"
x="Raster", y="SpatialLines"
x="Raster", y="SpatialPoints"
x="Raster", y="SpatialPolygons"
x="Raster", y="vector"

これらのメソッドのいずれかのソースコードを表示するには、署名全体を指定する必要があります。

getMethod("extract" , signature = c( x = "Raster" , y = "SpatialPolygons") )

部分的な署名を提供するだけでは不十分です

getMethod("extract",signature="SpatialPolygons")
#Error in getMethod("extract", signature = "SpatialPolygons") : 
#  No method found for function "extract" and signature SpatialPolygons

エクスポートされていない関数を呼び出す関数

以下の場合はts.union.cbindtsおよび.makeNamesTsからアンエクスポート機能しているstats名前空間。:::演算子またはを使用して、エクスポートされていない関数のソースコードを表示できますgetAnywhere

> stats:::.makeNamesTs
function (...) 
{
    l <- as.list(substitute(list(...)))[-1L]
    nm <- names(l)
    fixup <- if (is.null(nm)) 
        seq_along(l)
    else nm == ""
    dep <- sapply(l[fixup], function(x) deparse(x)[1L])
    if (is.null(nm)) 
        return(dep)
    if (any(fixup)) 
        nm[fixup] <- dep
    nm
}
<bytecode: 0x38140d0>
<environment: namespace:stats>

コンパイルされたコードを呼び出す関数

「コンパイル済み」とは、コンパイラパッケージによって作成されたバイトコンパイル済みのRコードを指すものではないことに注意してください。<bytecode: 0x294e410>上記の出力の行は、関数がバイトコンパイルされていることを示しており、Rコマンドラインからソースを表示できます。

機能その呼び出し.C.Call.Fortran.External.Internal、または.Primitiveあなたが完全に機能を理解したい場合は、コンパイルされたコードのソースを見てする必要がありますので、コンパイルされたコードにエントリーポイントを呼び出しています。RソースコードのこのGitHubミラーは、開始するのに適切な場所です。この関数pryr::show_c_sourceは、GitHubページに直接移動して呼び出すため、便利なツールに.Internalなり.Primitiveます。パッケージには、使用することができ.C.Call.Fortran、と.External。ただし、.Internalまたは.Primitiveではありません。これらは、Rインタープリターに組み込まれている関数を呼び出すために使用されるためです。

上記の関数の一部の呼び出しでは、コンパイルされた関数を参照するために、文字列の代わりにオブジェクトを使用する場合があります。そのような場合、オブジェクトは、クラスのものである"NativeSymbolInfo""RegisteredNativeSymbol"または"NativeSymbol"、オブジェクトを印刷すると、有用な情報が得られます。たとえば、optim呼び出し.External2(C_optimhess, res$par, fn1, gr1, con)C_optimhessではなく、であることに注意してください"C_optimhess")。 optimはstatsパッケージに含まれているため、入力stats:::C_optimhessして、呼び出されているコンパイル済み関数に関する情報を確認できます。

パッケージ内のコンパイルされたコード

コンパイルされたコードをパッケージで表示する場合は、パッケージソースをダウンロード/解凍する必要があります。インストールされているバイナリでは不十分です。パッケージのソースコードは、パッケージが最初にインストールされたのと同じCRAN(またはCRAN互換)リポジトリから入手できます。このdownload.packages()関数は、パッケージソースを取得できます。

download.packages(pkgs = "Matrix", 
                  destdir = ".",
                  type = "source")

これにより、Matrixパッケージのソースバージョンがダウンロードされ、対応する.tar.gzファイルが現在のディレクトリに保存されます。コンパイルされた関数のソースコードsrcは、圧縮されていない、風袋引きされていないファイルのディレクトリにあります。解凍と風袋引きの手順は、関数を使用してR、の外部または内部から実行できます。ダウンロードと拡張のステップを1つの呼び出しに組み合わせることができます(この方法でダウンロードおよび解凍できるパッケージは一度に1つだけであることに注意してください)。Runtar()

untar(download.packages(pkgs = "Matrix",
                        destdir = ".",
                        type = "source")[,2])

または、パッケージ開発がパブリックにホストされている場合(GitHubR-ForgeRForge.netなど)、ソースコードをオンラインで閲覧できます。

基本パッケージでコンパイルされたコード

特定のパッケージは「基本」パッケージと見なされます。これらのパッケージはRで出荷し、そのバージョンが含まR.例のバージョンにロックされているbasecompilerstats、とutils。そのため、上記のようにCRANで個別にダウンロード可能なパッケージとして利用することはできません。むしろ、それらは/src/library/。の下の個々のパッケージディレクトリのRソースツリーの一部です。Rソースにアクセスする方法については、次のセクションで説明します。

Rインタープリターに組み込まれたコンパイル済みコード

Rインタープリターに組み込まれているコードを表示する場合は、Rソースをダウンロード/解凍する必要があります。または、RSubversionリポジトリまたはWinstonChangのgithubミラーを介してオンラインでソースを表示できます。

Uwe LiggesのRニュース記事(PDF)(p。43 )は、.Internalおよび.Primitive関数のソースコードを表示する方法の優れた一般的なリファレンスです。基本的な手順は、最初にで関数名をsrc/main/names.c検索し、次にのファイルで「Cエントリ」名を検索することですsrc/main/*

100
smci 2014-05-23 12:46.

この質問とその重複上の他の回答に加えて、ここではそれがでますどのパッケージ知らなくても、パッケージの機能のためのソースコードを入手するには良いの方法です私たちはソースをしたい場合などは言います。randomForest::rfcv()

表示/編集ポップアップウィンドウでそれを:

edit(getAnywhere('rfcv'), file='source_rfcv.r')

View(getAnywhere('rfcv'), file='source_rfcv.r')

edit()(ユーザーが選択した)テキストエディタを開き View()ますが、スプレッドシートスタイルのデータビューアを呼び出すことに注意してください。

  • View()(複数列の)データの閲覧には最適ですが、通常、おもちゃの長さ以外のコードにはひどいものです。
  • したがって、コードのみを表示したい場合、edit()IMOは実際にはよりもはるかに優れView()ていedit()ます。これを使用すると、R関数の最大70%を占める可能性のあるすべての引数解析/チェック/デフォルト/エラーメッセージロジックを折りたたむ/非表示にする/ダミーにすることができます、そして関数が実際に何かを実行する部分(!)、戻り値の型がどのタイプのオブジェクトであるか、再帰するかどうか、どのように再帰するかなどに到達します。

するには、別のファイルにリダイレクト(あなたのお気に入りのIDE /エディタでコードを持ち出すことができるように/ etc grepを/でそれを処理します。):

capture.output(getAnywhere('rfcv'), file='source_rfcv.r')
26
Selva 2014-08-12 21:01.

debug()関数を使用してデバッグすると表示されます。t()転置関数の基礎となるコードを見たいとしましょう。「t」と入力するだけでは、あまりわかりません。

>t 
function (x) 
UseMethod("t")
<bytecode: 0x000000003085c010>
<environment: namespace:base>

ただし、「debug(functionName)」を使用すると、基礎となるコードが明らかになり、内部がなくなります。

> debug(t)
> t(co2)
debugging in: t(co2)
debug: UseMethod("t")
Browse[2]> 
debugging in: t.ts(co2)
debug: {
    cl <- oldClass(x)
    other <- !(cl %in% c("ts", "mts"))
    class(x) <- if (any(other)) 
        cl[other]
    attr(x, "tsp") <- NULL
    t(x)
}
Browse[3]> 
debug: cl <- oldClass(x)
Browse[3]> 
debug: other <- !(cl %in% c("ts", "mts"))
Browse[3]> 
debug: class(x) <- if (any(other)) cl[other]
Browse[3]>  
debug: attr(x, "tsp") <- NULL
Browse[3]> 
debug: t(x)

編集: debugonce()はundebug()を使用せずに同じことを達成します

22
Geoffrey Poole 2016-12-31 11:41.

非プリミティブ関数の場合、Rベースには、関数body()の本体を返すと呼ばれる関数が含まれます。たとえば、print.Date()関数のソースを表示できます。

body(print.Date)

これを生成します:

{
    if (is.null(max)) 
        max <- getOption("max.print", 9999L)
    if (max < length(x)) {
        print(format(x[seq_len(max)]), max = max, ...)
        cat(" [ reached getOption(\"max.print\") -- omitted", 
            length(x) - max, "entries ]\n")
    }
    else print(format(x), max = max, ...)
    invisible(x)
}

スクリプトで作業していて、関数コードを文字ベクトルとして使用したい場合は、それを取得できます。

capture.output(print(body(print.Date)))

あなたを取得します:

[1] "{"                                                                   
[2] "    if (is.null(max)) "                                              
[3] "        max <- getOption(\"max.print\", 9999L)"                      
[4] "    if (max < length(x)) {"                                          
[5] "        print(format(x[seq_len(max)]), max = max, ...)"              
[6] "        cat(\" [ reached getOption(\\\"max.print\\\") -- omitted\", "
[7] "            length(x) - max, \"entries ]\\n\")"                      
[8] "    }"                                                               
[9] "    else print(format(x), max = max, ...)"                           
[10] "    invisible(x)"                                                    
[11] "}"     

なぜそんなことをしたいのですか?リストに基づいてカスタムS3オブジェクト(x、where class(x) = "foo")を作成していました。リストメンバーの1つ(「fun」という名前)は関数でありprint.foo()、関数のソースコードをインデントして表示したいと思いました。だから私は次のスニペットになってしまいましたprint.foo()

sourceVector = capture.output(print(body(x[["fun"]])))
cat(paste0("      ", sourceVector, "\n"))

に関連付けられたコードをインデントして表示しますx[["fun"]]

18
MichaelChirico 2015-12-02 10:18.

これが主な答えの流れにどのように適合するかはわかりませんでしたが、しばらくの間私を困惑させたので、ここに追加します:

中置演算子

いくつかの基本中置演算子(例えば、のソースコードを参照するには%%%*%%in%)、使用getAnywhere、例えば:

getAnywhere("%%")
# A single object matching ‘%%’ was found
# It was found in the following places
#   package:base
#   namespace:base
#  with value
#
# function (e1, e2)  .Primitive("%%")

主な答えは、ミラーを使用してより深く掘り下げる方法をカバーしています。

10
Eric 2014-12-05 13:39.

Rには非常に便利な機能があります edit

new_optim <- edit(optim)

optimRで指定したエディタを使用したソースコードを開き、options編集して変更した関数をに割り当てることができますnew_optim。この関数は、コードを表示したり、コードをデバッグしたりするのに非常に気に入っています。たとえば、メッセージや変数を出力したり、さらに調査するためにグローバル変数に割り当てたりすることもできます(もちろん使用できますdebug)。

ソースコードを表示したいだけで、面倒な長いソースコードをコンソールに出力したくない場合は、次を使用できます。

invisible(edit(optim))

明らかに、これを使用してC / C ++またはFortranのソースコードを表示することはできません。

ところで、editリスト、マトリックスなどの他のオブジェクトを開くことができます。これにより、データ構造と属性も表示されます。関数deを使用して、Excelのようなエディター(GUIがサポートしている場合)を開いて、行列またはデータフレームを変更し、新しいものを返すことができます。これは便利な場合もありますが、通常の場合、特にマトリックスが大きい場合は避ける必要があります。

8
MCH 2017-01-25 06:42.

関数がC / C ++ / Fortranではなく純粋なRで記述されている限り、次のものを使用できます。それ以外の場合は最良の方法はされてデバッグ「を使用してとジャンプ 」:

> functionBody(functionName)
7
Arthur Yip 2019-02-23 04:54.

RStudioには、(少なくとも)3つの方法があります。

  1. カーソルが任意の機能にあるときにF2キーを押します。
  2. CtrlキーまたはCommandキーを押しながら関数名をクリックします
  3. View(function_name)(上記のとおり)

ソースコードを含む新しいペインが開きます。.Primitiveまたは.Cに到達した場合は、別の方法が必要になります。申し訳ありません。

5
strboul 2017-12-27 01:45.

print.function()S3ジェネリックであるを使用して、コンソールで関数writeを取得することもできます。

5
Koo 2017-01-11 16:45.

View(function_name)-例:View(mean)必ず大文字の[V]を使用してください。読み取り専用コードがエディターで開きます。

Related questions

MORE COOL STUFF

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは、夫に会ったとき、典型的な交際のアドバイスに逆らいました。

マイケルシーンが非営利の俳優である理由

マイケルシーンが非営利の俳優である理由

マイケルシーンは非営利の俳優ですが、それは正確にはどういう意味ですか?

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

特徴的なスターのコリン・エッグレスフィールドは、RomaDrama Liveでのスリル満点のファンとの出会いについて料理しました!加えて、大会での彼のINSPIREプログラム。

「たどりつけば」をオンラインでストリーミングできない理由

「たどりつけば」をオンラインでストリーミングできない理由

ノーザンエクスポージャーが90年代の最も人気のある番組の1つになった理由を確認するには、Blu-rayまたはDVDプレーヤーをほこりで払う必要があります。

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖は、世界で2番目に大きいボイリング湖です。そこにたどり着くまでのトレッキングは大変で長いですが、努力する価値は十分にあります。

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

サロンからのヘアトリミングや個人的な寄付は、油流出を吸収して環境を保護するのに役立つマットとして再利用できます。

ホワイトハウスの最も記憶に残る結婚式を見てください

ホワイトハウスの最も記憶に残る結婚式を見てください

過去200年以上の間にホワイトハウスで結婚したのはほんの数人です。彼らは誰でしたか、そしてそこで結婚式を獲得するために何が必要ですか?

ねえNFL、ジョーバロウとカイラーマレーは女性の権利をサポートするために少しの助けを使うことができます

ねえNFL、ジョーバロウとカイラーマレーは女性の権利をサポートするために少しの助けを使うことができます

ジョー・バロウロー対ウェイド事件の転覆に対応するNFLは、言葉を言わないことで、腹立たしいが予測可能なPRの結果でした。

別の日、別のヒンジのないLIV記者会見

別の日、別のヒンジのないLIV記者会見

(lから)パット・ペレス、ブルックス・ケプカ、パトリック・リードサウジアラビアのLIVゴルフリーグのさらに別の信じられないほどの記者会見で、スポーツのファンはブルックス・ケプカからでたらめな吐き気と質問回避の驚異的なマスタークラスを受けました。パトリックリード、ブライソンデシャンボー、パットペレス、最近のPGAツアーの脱北者。

ミズ・マーベルの家族の帰郷は悪役よりも激しく打撃を与える

ミズ・マーベルの家族の帰郷は悪役よりも激しく打撃を与える

レッドダガーとマーベルさんがチームを組んでいます。

6億7500万ドルのビットコインローンのデフォルト後にすべての資産を清算するように命じられたスリーアローズキャピタル

6億7500万ドルのビットコインローンのデフォルト後にすべての資産を清算するように命じられたスリーアローズキャピタル

暗号業界最大の沈没船の1つであるスリーアローズキャピタルは、ついにその悲惨さから解放されています。火曜日に、不良債権ヘッジファンドは、債権者からの返済を要求する訴訟の高まりに応えて、バージンアイランド裁判所によって清算を命じられました彼らが3ACに行ったローン。

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya shared a sweet photo in honor of boyfriend Tom Holland's 26th birthday Wednesday

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

シーレン「Ms.JuicyBaby」ピアソンは、先月脳卒中で入院した後、「もう一度たくさんのことをする方法を学ばなければならない」ため、言語療法を受けていることを明らかにしました。

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

オスカー受賞者の世紀半ばの家には、3つのベッドルーム、2つのバス、オーシャンフロントの景色があります。

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、生後4か月の娘、モナコに母乳育児をしていると語った。

Suffragettes Indicam #3: Junho

Suffragettes Indicam #3: Junho

Mais um mês se findando — e metade do ano de 2022 já passou. Sabe o que isso significa? Não, não é hora de verificar se você está cumprindo com suas resoluções de Ano Novo.

多元宇宙—Junø

多元宇宙—Junø

チェーン間アカウントがJunoに登場します。異なるブロックチェーン間でスマートコントラクトの構成可能性と真の相互運用性を提供します。

#brand【ベター・コール・ソール!アメリカのテレビシリーズ「ブレイキング・バッド」に最高のビジネス例が隠されている】・・・ルールクリエイティブ

#brand【ベター・コール・ソール!アメリカのテレビシリーズ「ブレイキング・バッド」に最高のビジネス例が隠されている】・・・ルールクリエイティブ

1.ドラマを見た後、起業する考えはありますか?あなたのビジネスはボトルネックに遭遇しましたか?方向性がなくてわからない場合は、ドラマを追いかけて行くことを心からお勧めします。(?)ブラフではなく、最も完璧なビジネス例を隠すドラマがあります。2.ブレイキング・バッドとその弁護士ドラマ「ブレイキング・バッド」を見た友人たちは、演劇の中で、穏やかな表情で、弁護士のソウル・グッドマンに深く感銘を受けなければなりません。口を開けて、感覚の弱い傭兵の性格を持っています。道徳の面で、サル・グッドマンは無意識のうちに劇に欠かせない役割を果たし、彼自身のシリーズ「絶望的な弁護士」(ベター・コール・ソール)を生み出しました。ウェントウのテキストとビデオは、劇中のソウル・グッドマンのテレビコマーシャルです。製品(サービス)、競争戦略、市場ポジショニング、ブランド名、ターゲット顧客グループ、コミュニケーション軸から広告まで、サル・グッドマンの役割のビジネス設定は、「最低」と見なすことができる超超超超超超完全です。ブランドコミュニケーションのコスト」「変化」のモデル。なぜ?私の分析をご覧ください。3.ソウル・グッドマンの「事業戦略」1.基本情報ブランド名:Saul Goodman製品:法律相談サービス対象顧客:麻薬中毒、飲酒運転、事故など。法律知識の欠如は、一般的に公立弁護士にしか余裕がなく、真面目な弁護士も「特別な法律を持つ消費者」を避けます。恐れてはいけない「​​ニーズ」。コミュニケーションの主軸:この国のすべての男性、女性、子供は有罪判決を受けるまで無実だと思います。地域:アルバカーキ市スローガン:Thrallに電話したほうがいいです!(ベター・コール・ソール)広告:2つの可能性のある犯罪状況をシミュレートします+サウルの主張+サウルのスローガン2をより適切に呼び出します。

メインネットガイド— Arbitrum Odyssey Week 2

メインネットガイド— Arbitrum Odyssey Week 2

最新のアップデートを受け取るために私たちに従ってください。ニュースレター:https://www。

Language