named routesでtransit_sidが動かない

投稿者 nanki 2008-02-01 11:50:00 GMT

person_urlとかにsession_idがつかないと思ったら、最適化のためのコードが、defaulturloptionsを無視するらしい。

#10925 (Routing optimization, named routes missing default url options) - Rails Trac - Trac


今日のHaskell

投稿者 nanki 2008-01-26 19:55:00 GMT

フィボナッチ数列。

readを見つけるのに、どれだけの時間を費やしたことか。
まだ、>>=の意味も、結合の優先順位も正確にはわかってないのでおそるおそる。

import System

fib :: Int -> Int
fib 0 = 0
fib 1 = 1
fib n = (fib $ n - 1) + (fib $ n - 2)

main = getArgs >>= print . fib . read . head

distcc動かない

投稿者 nanki 2008-01-22 21:00:00 GMT

起動しなくなったまま放置していたgentooマシンを久しぶりにいじる。

起動しないので、Knoppixで起動して無理矢理emerge --systemとか実行していると、

ACCESS DENIED  open_wr:   /.distcc/lock/cpu_localhost_0

とのこと。

解決法は、

# in /etc/make.conf
-  DISTCC_DIR="${PORT_TMPDIR}/.distcc
+ #DISTCC_DIR="${PORT_TMPDIR}/.distcc

わかるわけない。

参考:

BenchmarkForRails導入でrakeが動かない

投稿者 nanki 2007-12-28 11:10:00 GMT
 ♞ rake test:units
(in /Users/nanki/work/...../trunk)
rake aborted!
undefined method `watch' for BenchmarkForRails:Module

これは困った。

AutoLoadingがうまくいっていないようだが、この手の問題は追跡が難しい。 とりあえず適当な箇所で、require 'benchmark_for_rails'しておけば大丈夫だが、気持ち悪いので次の日原因を追ってみた。

p追跡の結果だけ書くと、rake 実行時に読み込まれるlogs.rake冒頭でのrequireで、BenchmarkForRailsモジュールが初期化されて、本来読まれて欲しいはずの、benchmark_for_rails.rbがロードされないのが問題。

# in vendor/plugins/benchmark_for_rails/tasks/logs.rake
require File.dirname(__FILE__) + '/../lib/parsing.rb'
require File.dirname(__FILE__) + '/../lib/report.rb'

対処法はこちらの通り。

と思ったら、今朝五時に直ってるじゃないの。

参考:


Kanasan.JS#2

投稿者 nanki 2007-12-11 00:34:00 GMT

朝九時から夜九時まで、prototype.jsを読む、という勉強会が開催されていたので、夕方の数時間だけオンラインで参加。 読んでいるソースのバージョンが違っていて、行数指定の話の内容を勘違いしていた。

僕が読んだ範囲は、prototype.js v1.6.0 l.587 - l.1193, Enumerable - Ajax.Baseまで。

Kanasan.JS本体の人はもっと広いはず。

Enumerable

l.587

Rubyと似たのが多いので、ほとんど違和感無く読める。 each の実装は_eachのみに依存して、他のメソッドはeachのみに依存している。

l.775

zipの実装がなかなか素敵。

こんな使い方。

>> [1, 2, 3].zip([1, 2, 3], [1, 2, 3]);
[[1, 1, 1], [2, 2, 2], [3, 3, 3]]

>> var sum = function(r,m) { return r + m };
>> [1, 2, 3].zip([1, 2, 3], [1, 2, 3], function(e){return e.inject(0, sum)})
[3, 6, 9]
// l.775
  zip: function() {
    var iterator = Prototype.K, args = $A(arguments);
    if (Object.isFunction(args.last()))
      iterator = args.pop();

    var collections = [this].concat(args).map($A);
    return this.map(function(value, index) {
      return iterator(collections.pluck(index));
    });
  }

[this].concat(args).map($A)と、collections.pluck(index) がキモ。

Array

l.813

WebKitでは、NodeList#toArrayにネイティブ実装を使う。 できれば、パフォーマンスのためのコードは、一目でわかるようにしておいて欲しいorおきたい。 パフォーマンスのためなのか、互換性のためなのかがわからない。(できればかかわりたくない)

l.837

this.length = 0;で配列の初期化ができるとは、知らなかった。 ちなみに、元の長さより長くすると、undefinedでpadされる。

l.877

array.uniq遅そう。 arrayがソート済みの場合、array.uniq(true)でずいぶん速くなりそう。 次のintersectもdetectで遅そうだけど、arrayはEnumerableであれば何でもよさそうなので、これでいいか。 気をつけて使う。 Enumerableって、極端な話、each実行するたびに結果が違ってもいいんだもんな。

Number

l.956

toColorPart:0-255の値を2桁16進にするためのコード。

l.979

Math.ceil とかをNumber#ceilにしてる。methodize().

Hash

l.987

いきなりのif文がわけわからないが、なにかの挙動の違いで、パフォーマンスをあげようとしているのだろうか。 v1.6.0.1ではなくなっているので、あまり気にしないで読み進む。

eachの中で、pair.key, pair[0] の両方のアクセス方法を許すようなコードが書かれている。

l.1016

この書き方(無名関数の中で関数を作って、return でオブジェクトを返す)は、JavaScriptでプライベート関数を実現するイディオムのようなもので、 この場合は、toQueryPairは、外からはアクセスできない。

1.5時代のソースも見てみると、Hashががらりと変わっていることに気がつく。 1.5では、値をthis自身に、1.6では、値をthis._objectに格納している。

// 1.5
$H({a: 3})["a"] // => 3

// 1.6
$H({a: 3})["a"] // => undefined
$H({a: 3}).get("a") // => 3
$H({a: 3}).toObject()["a"] // => 3

うーん、これは結構使ってしまっている気がするんだなぁ。

l.1072

toQueryString 突然のcurryに緊張が走る。 配列をQueryStringに変換する際、toQueryPairの第一引数を固定しているだけのようだ。

>> $H({a: [1,2,3]}).toQueryString()
"a=1&a=2&a=3"

そういえば、最近、近所の交差点がcurry激戦区になりつつある。

l.1100

toTemplateReplacements. どうも、1.5, 1.6間でHashの実装が大きく変わったのは、これが原因のような気もする、この関数。 evaluateの中で勝手に呼ばれるので、気にする事はない。

//v1.5
>> (new Template("hello #{name} #{each}.")).evaluate($H({name: 'ujihisa'}))
"hello ujihisa function (iterator) {
....
...
}."

//v1.6
>> (new Template("hello #{name} #{each}.")).evaluate($H({name: 'ujihisa'}))
"hello ujihisa ."

ObjectRange

RubyのRangeみたいなの。 Range だと、DOMのRangeとかぶるので、ObjectRangeらしい。 exclusiveは、最後の要素を含まないか含むか。

start, endは、比較可能で、succが実装されていれば何でもよい。 比較も、オーバライド可能なメソッドにしてほしいな。

Arrayは比較可能なので、Array.prototype.succを実装すると、ObjectRangeで使えるようになると思う。 あんまり意味なさそうだけど。

$R("a", "c").map()
// => ["a", "b", "c"]

Array.prototype.succ = function() {
  var clone = this.clone();
  clone.push(this.last());
  return clone;
}

$R([1], [1,1,1]).map()
// => [[1], [1, 1], [1, 1, 1]]

Ajax.Responders

Ajaxのリクエストに関するイベントリスナを管理している。

l.1162

なぜapplyの第一引数がresponderなのか、という話題になる。 たぶん、こういう使い方をしたいから、という気がする。

Ajax.Responders.register({onComplete: function () { Ajax.Responders.unregister(this)}});

Ajax.Base

あんまり読みどころがない。 目がAjax.Requestの中の$superを見つけてしまう。なんだこれ。

$super

  initialize: function($super, url, options) {
    $super(options);

という使われ方から、親クラスのメソッドを呼び出す関数だというのはわかるのだが・・・

$superで検索すると、文字列として見つかる。あやしい。

  1. value には関数が入る。
  2. value.argumentNames()で関数宣言のソース文字列を正規表現でパースし、引数のリストを取得して、
  3. 第一引数が$superならば、その関数を置き換えている。
  4. function() { return ancestor[m].apply(this, arguments) }; が$superの中身。
  5. wrapで、method(arg1, arg2) という呼び出しを、method($super, arg1, arg2) に置き換えつつ、
  6. 置き換えた事を悟られないように、toString, valueOfをオーバーライドしている。

嘘を嘘で塗り固めたような・・・。

//l.76
Class.Methods = {
  addMethods: function(source) {
    var ancestor   = this.superclass && this.superclass.prototype;
    var properties = Object.keys(source);

    if (!Object.keys({ toString: true }).length)
      properties.push("toString", "valueOf");

    for (var i = 0, length = properties.length; i < length; i++) {
      var property = properties[i], value = source[property];
      if (ancestor && Object.isFunction(value) &&
          value.argumentNames().first() == "$super") {
        var method = value, value = Object.extend((function(m) {
          return function() { return ancestor[m].apply(this, arguments) };
        })(property).wrap(method), {
          valueOf:  function() { return method },
          toString: function() { return method.toString() }
        });
      }
      this.prototype[property] = value;
    }

    return this;
  }
};

本筋とは関係ないけど、if (!Object.keys({ toString: true }).length) というコードを見ると、一瞬困惑するRuby脳。

おまけ

l.1222

      else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
        params += '&_=';

この謎の&_=、Safariのどれかのバージョンで、POSTのリクエストの後ろに変な文字列をつけるバグへの対策らしい。&_=........となるので、切り捨てられる。

参考:

OSXのユーザ辞書の作り方

投稿者 nanki 2007-11-26 04:20:00 GMT

Leopardからは、小学館の辞書データとWikipediaが追加されて、とっても便利なDictionary.app.

たぶん、キーボード使用を前提とした小気味よいインターフェースがいいんだと思う。 慣れてしまうと、もう生のWikipediaを使う気はなかなか起きない。

こうなると、なんでもかんでも、同じインターフェースで済ませたくなるもので、そんな時に、こんな検索しにくいページを見たら、「Dictionary.appで検索できて然るべき」と思ってしまうのが自然な流れ。

というわけで、ライフゲームの辞書、Life LexiconをDictionary.app用に変換します。

まずは、テンプレートをコピーしてくる。 試しにmakeすると、あっさり辞書が作られる。 make installすれば、~/Library/Dictionaries 以下にコピーされ、Dictionary.appから検索できる状態になる。(Dictionary.appの環境設定で有効にしないとだめかも)

$ cp -r /Developer/Examples/Dictionary Development Kit/project_templates dict
$ cd dict
$ make
"""/Developer/Extras/Dictionary Development Kit"/bin"/build_dict.sh"  "My Dictionary" MyDictionary.xml MyDictionary.css MyInfo.plist
- Building My Dictionary.dictionary.
- Cleaning objects directory.
- Preparing dictionary template.
- Preprocessing dictionary sources.
- Extracting index data.
- Preparing dictionary bundle.
- Adding body data.
- Preparing index data.
- Building key_text index.
- Building reference index.
- Fixing dictionary property.
- Copying CSS.
- Copying other resources.
- Finished building ./objects/My Dictionary.dictionary.
echo "Done."
Done.

重要なのは、MyDictionary.xmlファイル。 辞書の元となるデータをパースして、XMLファイルを作ってやる。

<?xml version="1.0" encoding="UTF-8"?>                                                                               
<d:dictionary xmlns="http://www.w3.org/1999/xhtml" xmlns:d="http://www.apple.com/DTDs/DictionaryService-1.0.rng">    
  <d:entry id="blinker puffer" d:title="blinker puffer">                                                             
    <d:index d:value="blinker puffer" d:title="blinker puffer" />                                                    
    <d:index d:value="puffer" d:title="blinker puffer" />                                                            
    <h1><span class="headword">blinker puffer</span></h1>                                                            
    <span class="meaning">Any <a href="x-dictionary:r:puffer">puffer</a> whose output is <a href="x-dictionary:r:blinker">blinker</a>s.  However, the term is particularly used for p8 c/2 puffers.  ....
    </span>
  </d:entry>
  <!-- 以下d:entry の山 -->
</d:dictionary>

意味はほとんど見た目通り。
それぞれの項目は、インデックスと内容のXHTMLで構成される。 他の単語を参照する、href=”x-dictionary:r:ID”とかが特徴的か。 上の例では「blinker puffer」という単語に対して、pufferでも検索に引っかかって欲しいので、indexに加えてある。

パースしてXMLを吐くコードは、汎用性がないのでここには載せないが、今回は以下のようなLifeを表す図を、rcairoでpng画像に変換もしている。

OO..
O..O
..OO

画像などのリソースは、dict/OtherResources 以下の適当な場所に置いておき、普通のHTMLのように、<img>タグを使って埋め込む。

<p><img src="Images/blinker%20puffer_0.png"/></p>

これで、

$ make
$ make install

すれば、ユーザ辞書の完成。

続き

さて、これだけで終わりではもったいないので、先日作ったQuartz Compositionを組み込めないか、頑張ってみる。

HTMLにQuartz Compositionを組み込むのは簡単で、EMBEDタグを使って、

<embed id="composition" type="application/x-quartzcomposer" src="LifeLexicon.qtz" width="300px" height="300px" />

とする。

これで、普通のムービーならスタートするのだけど、ライフゲームなので第0世代の画像を渡してやらないといけない。

Quartz ComposerのWebKitプラグインにはJavaScript APIが用意されていて、publishしたパラメータを設定できるようになっている。 が、文字列しか設定できないようだ。画像はどうやって渡すのだろう。

調べてみると、Compositionの中で、Image Downloaderというパッチを使うらしい。 Image Downloaderは指定されたURLの画像をImageとして出力するパッチ。 なるほど。 ImageDownloaderの入力を、imageLocationという名前でPublishして・・・

var composition = document.getElementById("composition");
composition.setInputValue("imageLocation", "fullpath.png");

こんな感じになるのかな。 しかし、フルパス指定じゃないといけないのが面倒だなぁ・・・

先生、こちらにできあがったものが用意してあります。

結局、location.href と、EMBEDに勝手に付け加えたimage属性から、フルパスを取得する仕組みに。 文中のSpaceはCompositionというか、Universeというか。

//LifeLexicon.js
(function () {
  var waitForSpaces = function (spaces) {
    if (spaces.length == 0) return;

    if (spaces[0].loaded && spaces[0].loaded()) {
      var space = spaces.shift();
      var base = location.href.substr(0, location.href.lastIndexOf("/"))
      space.setInputValue("imageLocation", base + space.getAttribute('image'));
    } 
      
    with ({callee: arguments.callee}) {
      setTimeout(function () {callee(spaces)}, 100);
    }
  };

  var arrayFromNodeList = function (nodelist) {
    var result = [];
    for (var i = 0; i < nodelist.length; i++) {
      result.push(nodelist.item(i));
    }
    return result;
  };

  waitForSpaces(arrayFromNodeList(document.getElementsByTagName('EMBED'))); 
})();

なぜか、<script src="LifeLexicon.js">だと読み込まれないので、

<script>
  var tag = document.createElement("SCRIPT");
  tag.src = "./LifeLexicon.js";
  document.getElementsByTagName("HEAD")[0].appendChild(tag);
</script>

というコードも、<d:entry>内に埋め込むように。

これで「生きた」LifeLexiconが完成。

LifeLexicon

CREDITをどこかに入れないと配布できないらしいので、欲しい人には直接送ります。 いないだろうけど。

誰か、Ruby Reference Manualをこれで。

参考:

Quartz Composer - Conway's Game of Life - 宇宙大決戦

投稿者 nanki 2007-11-18 04:17:00 GMT

9月から半分Macユーザになったので、Macの開発環境も触ってみよう思い、まずは楽しそうなQuartz Composerに手を出してみた。

基本的には、Patchと呼ばれる部品をつなぎ合わせてプログラミングしていくものだが、ProgrammableなPatchも三種類(JavaScript, GLSL, Kernel Language?)用意されていて、後者二つは最近流行?のベクトル指向な言語。

以前から、GPUのシェーダ言語でライフゲームを書いて見たかったので、テーマはライフゲームに決定。 KOF2007の懇親会で、小波先生、池上さんとライフゲームの話題で盛り上がったのも理由。

メインとなるKernel Languageのコードは以下。 画像のある一点の色を決めるコードを書けば、あとは勝手にベクトル化してくれているはず。
(たぶん、ベクトル化のために)普通のif文は使えないので、compare関数を使う。

kernel __color conway(sampler image)
{
    float self = sample(image, samplerCoord(image)).r;

    float lives;
    lives  = sample(image, samplerCoord(image) + vec2( 1, -1)).r;
    lives += sample(image, samplerCoord(image) + vec2( 0, -1)).r;
    lives += sample(image, samplerCoord(image) + vec2(-1, -1)).r;
    lives += sample(image, samplerCoord(image) + vec2( 1,  0)).r;
    lives += sample(image, samplerCoord(image) + vec2(-1,  0)).r;
    lives += sample(image, samplerCoord(image) + vec2( 1,  1)).r;
    lives += sample(image, samplerCoord(image) + vec2( 0,  1)).r;
    lives += sample(image, samplerCoord(image) + vec2(-1,  1)).r;

    const float dead  = 0.0;
    const float alive = 1.0;
    float compare4 = compare(lives - 3.5, alive, dead);

    float r = compare(
        self - 0.5,
        compare(lives - 2.5, dead, compare4),
        compare(lives - 1.5, dead, compare4)
    );
    
    return __color(r, r, r, 1);
}

それから、1step前の状態が必要なので、JavaScriptで以下のようなPatchも作成。 フレームをまたがって値を保持するには、ObjectかMathのプロパティに値を入れておけばよい。

function (__image output) main (__image input, __image initial, __number dummy) {
  var result = {output: Object.prev || initial};
  Object.prev = input;
  return result;
}

後は適当にPatchを組み合わせていけば、完成。
Apple Remoteでコントロールしたり、スクリーンセーバにしたり、1フレームで3step進めたりしなければ、もうちょっと単純になる。
quartz composer screenshot

ライフゲームのルールについてはWikipediaを参照していただくとして、自分の周囲9マスから次の状態を決定する、という非常にローカルで単純なルールから、あまりに複雑で大域的な発展が繰り広げられる様は、宇宙や生命といった壮大なものを連想させる。

max vs glider guns
ライフゲーマー必見!ものすごい勢いで宇宙を浸食するmaxと、MITが開発したグライダーガンの、宇宙を賭けた闘い。

参考:

ライフゲーム - Wikipedia


信号処理言語FAUST

投稿者 nanki 2007-08-29 03:05:00 GMT

DSP(Digital Signal Processing)用言語。
FAUST(Functional AUdio STream)

関数型言語で機能単位(ブロック?)を作り、あとはそのブロックを繋げるようにして全体を組み立てるらしい。 ノイズジェネレータとか、フィルター、アンプとかをケーブルで繋いで、変な音を作る様な感覚。

簡単なGUIを記述することもできて、パラメータをスライダやボタンで入力したりできるらしい。

ちょっと面白いのは、: <: :> , ~ といった記法で、ブロックダイアグラムを表現するあたり。 A の複数の出力をマージしてBの入力とする場合、A :> B と書けるそうな。 信号処理でよく使うフィードバックは ~

出力の数と入力の数が違ったりした場合のルールがよく分からないけど、ツボにはまれば楽しそう。

もう一つ興味深いことには、CVS版にLLVMのバックエンドがあるようで、この辺の実装も、力があれば眺めてみたい。自動でベクトル化(やりやすい分野なので)とかやってくれてそう。

ハードウェアのDSPにマッピングとかもやってくれないかしらん。

papers and documentationのPDFで一週間は楽しめそうだ。

参考:

Railsアプリケーションの国際化 - Globalize

投稿者 nanki 2007-08-26 10:15:00 GMT

Globalizeを使ってみる。

セットアップ

適当なRailsアプリを作って、Globalizeをインストール。

$ script/plugin install http://svn.globalize-rails.org/svn/globalize/trunk
....
$ mv vendor/plugins/trunk vendor/plugins/globalize
$ rake globalize:setup

CSV::Cellがinspectされたようなエラーが出るので、vendor/plugins/globalize/tasks/data.rake を修正する。

--- ./vendor/plugins/globalize/tasks/data.rake.orig     0000-00-00 00:00:00.000000000 +0000
+++ ./vendor/plugins/globalize/tasks/data.rake  0000-00-00 00:00:00.000000000 +0000
@@ -17,3 +17,3 @@

-    columns = reader.shift.map { |column_name| cnx.quote_column_name(column_name) }
+    columns = reader.shift.map { |column_name| cnx.quote_column_name(column_name.data) }
     column_clause = columns.join(', ')
@@ -24,3 +24,3 @@
       raise "No header defined"     unless column_clause
-      values_clause = row.map { |v| cnx.quote(v).gsub('\\n', "\n").gsub('\\r', "\r") }.join(', ')
+      values_clause = row.map { |v| cnx.quote(v.data).gsub('\\n', "\n").gsub('\\r', "\r") }.join(', ')
       sql = "INSERT INTO #{table_name} (#{column_clause}) VALUES (#{values_clause})"

さらに、vendor/plugins/globalize/data/language_data.csv の空行がエラーを起こしているので修正。

$ rake globalize:setup
...

成功。

View翻訳

base_languageを英語に。

# config/environment.rb
Globalize::Locale.set_base_language("en-US")
$ script/console
>> "March [month]".t
=> "March"
>> Globalize::Locale.set("ja-JP")
=> #<Globalize::Locale...
>> "March [month]".t
=> "3月"
>> Time.now.loc "%A"
=> "日曜日"

ふむふむ。この辺は、gettextの方が使いやすそうかなぁ。

Model翻訳

適当なモデルを作成

$ script/generate model Product
...
# db/migrate/001_create_products.rb
  def self.up
    create_table :products do |t|
      t.column :name, :string
      t.column :manufacturer, :string
    end
  end
$ rake db:migrate
$ script/console
>> p = Product.create :name => "Pucchin Pudding", :manufacturer => "Glico"
=> #<Product:...
>> p.name
=> "Pucchin Pudding"
>> p.manufacturer
=> "Glico"

# jaで保存。
>> Globalize::Locale.set("ja-JP")
>> p.name = "プッチンプリン"
>> p.manufacturer = "グリコ"
>> p.save
=> true

# jaで読む。
>> p.reload
>> p.name
=> "プッチンプリン"
>> p.manufacturer
=> "グリコ"

# enで読む。
>> Globalize::Locale.set("en-US")
>> p.reload
>> p.name
=> "Pucchin Pudding"
>> p.manufacturer
=> "Glico"

ちゃんと動いてる。

この時、productsテーブルにはbase_languageで格納され、それとは別にglobalize_translationsテーブルに、翻訳情報を保持している。

sqlite> SELECT * FROM globalize_translations WHERE id > 7088;
id          type              tr_key      table_name  item_id     facet       built_in    language_id  pluralization_index  text                   namespace
----------  ----------------  ----------  ----------  ----------  ----------  ----------  -----------  -------------------  ---------------------  ----------
7089        ModelTranslation              products    18          name        t           2723                              プッチンプリン
7090        ModelTranslation              products    18          manufactur  t           2723                              グリコ

Object#_が定義されていたので、gettextとケンカするかと思ったけど、一緒に動いた。 偶然かもしれないけど。

screenshot

そんなこんなで、↑こんなアプリケーションができてしまう。
はたして、使う機会は訪れるのか?

追記:

  • eager loadingを行う時は、:include_translatedを使う。
  • が、対応が中途半端で、user.product_nameとアクセスしないとだめっぽい。
class User
  belongs_to :product
end

user = User.find(:first, :include_translated => :product)

user.product.name #=> NG
user.product_name #=> OK
参考:

ぷにぷにSSE3

投稿者 nanki 2007-08-20 23:55:00 GMT

C++でDSLなXbyakが気になる今日この頃、cpuinfoを見てみると。

% cat /proc/cpuinfo
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 15
model           : 4
model name      : Intel(R) Pentium(R) D CPU 2.80GHz
...(snip)...
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx lm pni monitor ds_cpl cid cx16 xtpr
...(snip)...

sse3がないと思ったら、pniというのがそれらしい。 Prescott New Instructionsの略?商標の関係なのか、まだ名前が決まってなかったのか・・・。わかりにくい。

XbyakはRubyに移植してみたいなぁ。 アセンブリでがんばってもCから数倍しか速くならないのが、なんとも悲しいけど、 ネイティブコードの切り貼りに使えて楽しそうだからいい。

気がついたら、右も左もx86マシンだしね。

同じ?DSL系ではMUDAも気になる。

参考: