AIRからJavaScriptの関数を呼ぶ方法

ExternalInterface.call(“JS関数名”, parameter); ってやるのかと思ってたらそうじゃないみたいなのでメモしておきます。

air2jsTest.mxml

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    creationComplete="init(event);">

  <s:layout>
    <s:VerticalLayout/>
  </s:layout>

  <fx:Script>
    <![CDATA[
      private var htmlLoader:HTMLLoader;

      private function init(event:Event):void {
        htmlLoader = new HTMLLoader();
        htmlLoader.addEventListener(Event.COMPLETE, onComplete);
        //jsを埋め込んだhtmlをロードする
        htmlLoader.load(new URLRequest("./html/air2jsTest.html"));
      }

      private function onComplete(event:Event):void {
        //htmlLoader.window.JS関数名(引数)
        var response:String = htmlLoader.window.jsFunc("http://www.google.com/");
        trace(response);
      }
    ]]>
  </fx:Script>

</s:WindowedApplication>

src/html/air2jsTest.html

<html>
<head>
<title>air2jsTest</title>
  <script type="text/javascript" src="../js/xmlhttpreq.js"></script>
</head>
<body>
</body>
</html>

src/js/xmlhttpreq.js

function jsFunc(url) {
  var req = new XMLHttpRequest();
  req.open("GET", url, false);
  req.send(null);
  return req.responseText;
}

 

ix2015で効率よくコンフィグのバックアップを取る方法

0. 面倒なコンフィグ管理

現在我が家では複数台のルータを運用している。特にUniversi IXシリーズは安いのでホイホイ買ってしまって、VPN先まで自分が管理しているせいで管轄ルータの台数がそれなりに増えてきちゃった。

おおよそ、外側のIX2015とかのコンフィグはいじることがないのだけれど、内側のIX2015のコンフィグはちょくちょく書き換える事になる。

VPNの設定などで色々と大きくなってきたコンフィグなんだけど、そうなってくるとコンフィグの管理が重要になってくる。

特に、もうすでに複数台のルータとVPNを結んでいる状態で、メインのVPN拠点ルータのコンフィグが飛んでしまうとかなり困った状態になってしまう。なのでバックアップが必要だ。

また、VPN上のルーティングのあたりは、まだまだ実験段階だったりする項目もあったりして、コンフィグの世代管理、過去のコンフィグに遡ったりもしたい。

バックアップ+世代管理、となると純粋にSubversionを利用すれば万事オッケーなんだけれど、リポジトリにコミットをするのが意外に大変だったりする。

というのも基本的にコンフィグは、telnetでログインした後、show running-configなどで取得してそれをテキストに貼り付けて保存、とすることで保存されるからだ。

とくにこのコピーが面倒くさい。複数のページにまたがっているときにはtelnet越しに何ページかに分けてコピーする必要があり、途中の行を飛ばしていないか、重複しないか、などヘンに気を遣ってしまう。

1. tftp

と、さて、どうやらIX2015ではtftp機能を利用することで、コマンド一発でコンフィグが保存できるらしい。

Trivial File Transfer Protocol(トリビアル ファイル トランスファー プロトコル、TFTP)は、UDPを用いてコンピュータ間でファイルを転送するためのプロトコルである。FTPに比べて軽量・単純なプロトコルである。認証機能が無いためにユーザ名やパスワードを必要としない。ポート番号69をデフォルトとして使用する。

Trivial File Transfer Protocol - Wikipedia

Universi のIXシリーズに限らず、他社製のルータでもtftpを通じてファームのアップデートやコンフィグの取得、送信が出来る機種は多かったりする。

このIX2015でもtftpを通じてバックアップをとれるようなので試してみた。

2. FreeBSDでtftpdを立ててソコへコンフィグを置こうとしてみる

FreeBSDでtftpのサーバを立ててみる。最近のサーバ、デーモンは基本的には独立して動くんだけれど、tftpはinetdで動かすのが主流らしい。

自分も主流に倣ってinetdで動かしてみる。

FreeBSDでtftpdを動かすのはとても簡単らしい。

    1. /etc/inetdを編集して以下の行を追加
tftp            dgram   udp     wait    root    /usr/libexec/tftpd
tftpd -s /path/to/tftpboot
      1. /path/to/tftprootディレクトリを作成。これを忘れると起動しない、うまく動かない。
      2. /etc/rc.dにinetd_enable=”YES”を追記
      3. /etc/rc.d/inetd restartを実行 (kill -HUP inetdpid でも可)

まずはtftpでstartup-configの転送を試してみる

rt8(config)# tftp put startup-config  192.168.xxx.yyy:hogehoge
TFTP error - Unknown Error

なにやらエラーが出たみたい。
windowsでtftpサーバを立てて試してみる

rt8(config)# tftp put startup-config  192.168.xxx.zzz:hoge
TFTP transfer complete, 4885 bytes, MD5 = cfc64755de8076f8eab5e820a1542f13

うまくいけた。何が原因なんだろう。
サーバのログを漁ってみる。
サーバはFreeBSD + inetd + /usr/libexec/tftpd。ログはxferlogに出てた。

Jun 17 17:34:48 xxxx tftpd[98211]: 192.168.xxx.yyy: write request for hogehoge: error 102
Jun 17 17:36:23 xxxx tftpd[98215]: 192.168.xxx.yyy: write request for statup-config: error 102

どうやらリクエストは飛んできてるらしいけどエラーらしい。
man tftpdを見てみる

TFTPD(8)                FreeBSD System Manager's Manual               TFTPD(8)

NAME
     tftpd — Internet Trivial File Transfer Protocol server

(中略)

    -w      Allow write requests to create new files.  By default tftpd
             requires that the file specified in a write request exist.  Note
             that this only works in directories writable by the user speci‐
             fied with -u option

     -W      As -w but append a YYYYMMDD.nn sequence number to the end of the
             filename.  Note that the string YYYYMMDD can be changed with the
             -F option.

どうやら-wオプション、または-Wオプションをつけると良いらしい。-Wだとファイル名の末尾に日付とかを自動でつけるようになるらしい。なるほど。
inetd.confを書き換えてみる

ee /etc/inetd.conf

該当する行で

tftp    dgram   udp     wait    root    /usr/libexec/tftpd      tftpd -l -w -s /tftproot

inetdを再起動

%sudo /etc/rc.d/inetd restart
Stopping inetd.
Starting inetd.

再度転送してやる

rt8(config)# tftp put startup-config  192.168.xxx.yyy:hogehogeo.
TFTP transfer complete, 4885 bytes, MD5 = cfc64755de8076f8eab5e820a1542f13

うまくいった!

パラメータつけてPOST

リクエストのときのパラメータはObjectに入れてURLRequest#dataに渡すのかと思ってたら違ったのでメモ。

var req:URLRequest = new URLRequest("http://example.com");
req.method = URLRequestMethod.POST;
var params:URLVariables = new URLVariables();  //これを使う
params["onigiri"] = "ume";
params.otya = "iemon";    //こうでもOK
req.data = params;

var loader:URLLoader = new URLLoader();
loader.load(req);

wordpressにファイルをアップロードしたらパスワードとかが要求された!

wordpressにファイルをアップロードしたらパスワードとかが要求された!
具体的にはユーザ名とパスワードが求められる、BASIC認証のダイアログが出てくるよう


になってしまった。

別段、何かをしたっていうわけじゃなくて、単純に、純粋に、ファイルをアップロードして記事に貼り付けただけなのに・・・。

さっくりぐぐってみると同じような症状の人を発見。そしてそれに対する返答も発見。

wordpressのインストールディレクトリから/wp-content/uploads/にある下記の二つのファイルをチェックしてみな!
.htpasswd
.htaccess
WordPress &#8250; Support &raquo; server at WP-Files requires a user name for visitors

で、みてみると確かに.htacessとかが出来ちゃってる・・・。こんなの作った覚えがないのにな、って思いながら消す。消す。消す。

このファイルを消したらもうダイアログが出なくなりました。

excelでipアドレスの4オクテット目を抜き出したかった

excelでipアドレスの4オクテット目を抜き出したかった。

例) 192.168.123.234

オクテット => 8っつの塊の意。転じてアドレスの1バイトの塊を指す。1オクテット目は192、2オクテット目は168、3オクテット目は123、4オクテット目は234。

コレをエクセルにいれてマクロ?で抜き出して作業をしたかった。

普通の言語なら正規表現でさっくりいくんだけどそう簡単にはいかない、残念。

=MID(H3,FIND(".",H3,FIND(".",H3,FIND(".",H3,1)+1)+1),4)

wordpressのcodeについて

wordpressで

[/code]

 

って書くとソースコードとかを記述できる。
うちではsyntax highlighter evolvedってやつを使ってるけど、実はこれ以外にデフォルトで用意されているものがあるらしい。
そこに追加でフックしてるのがコイツ、syntax highlighter evolvedなんだね。
なのでデフォルトのオプションも有効みたい。
Posting Source Code « Support — WordPress.com

  • autolinks (true/false) — すべてのURLをクリック出来る状態(リンク)にする。デフォルト値はtrue。
  • collapse (true/false) — これをtrueにすると最初から内容が表示されない。最初は”ソースを表示”という文字列になっていて、訪問者がクリックすることで展開され見ることが出来る。デフォルト値はfalse。
  • firstline (数値) — この値を設定することでコードのナンバリング開始の値を変えることができる。デフォルト値は1。
  • gutter (true/false) — ナンバリングを表示させる。falseにすると表示されなくなる。デフォルト値はtrue。
  • highlight (カンマ区切りの数値) — ハイライト表示させたい行番号を列挙できる。例えば”4, 7, 19″とすると、それぞれ4行目、7行目、19行目がハイライトされる。
  • htmlscript (true/false) — すべてのHTML/XMLをハイライトする。PHPのようなHTMLとソースコードが混在している環境では便利。デフォルト値はfalse。そしてすべての(langで指定する)言語で動くわけではなく、いくつかの言語でのみ動作する。
  • light (true/false) — 軽量モード。ナンバリングとツールバーを表示しない。ほんの数行のコードのときにはこれをオンにすると良い。デフォルト値はfalse。
  • padlinenumbers (true/false/整数値) — ナンバリングのパディング(字詰め)を制御する。trueに設定すると自動的にパディングを行い、falseに設定するとパディングを行わない。整数を与えると強制的に指定された桁に字詰めを行う。100と与えると100桁でパディングするので、1行目には99個の0を先頭につけて表示する。
  • toolbar (true/false) — コード表示部分の右上にマウスホバーで表示されるツールバーを表示する。デフォルト値はtrue。
  • wraplines (true/false) — 一行というまとまりを区切る、ラインラッピングを行わないようにする。コード下部にでてくる水平のスクロールバーが表示されるようになる。たぶんデフォルト値はtrue。

left4dead2のサーバをlinuxで起動するときのコマンド

なんかvac secureをオンにすると蹴られちゃう人がいるのでvac secureをオフにした状態で起動。

shell> cd srcds/left4dead2
shell> ./srcds_run - game left4dead2 +port 21701 -secure 0 +ip 192.168.xx.xxx -insecure

ある日アップデートしろっていうログが流れてた。

Your server needs to be restarted in order to receive the latest update.
MasterRequestRestart

Ctrl+Cしてアップデートをかけてやる
必ずsteam実行ファイルがあるディレクトリに上がること!
最後に現在のディレクトリを -dirで与えてやること。ここで指定したディレクトリからleft4dead2っていうフォルダを探しに行くはず(もしくは作る)。

shell> cd ../        # left4deadのdirにいた場合
shell> ./steam -command update -game left4dead2 -dir ./
Checking bootstrapper version ...
Updating Installation
Updating 'left 4 dead 2 common' from version 91 to version 92

98.04%  downloading .//left4dead2/bin/gameui.dll
99.12%  downloading .//left4dead2/left4dead2/modelsounds.cache
99.14%  downloading .//left4dead2/left4dead2/steam.inf
99.56%  downloading .//left4dead2/update/resource/ui/l4d360ui/blogpost.txt
99.92%  downloading .//left4dead2/update/resource/ui/l4d360ui/blogpost00.res
100.00% downloading .//left4dead2/update/resource/ui/l4d360ui/blogvote00.res

Checking/Installing 'left 4 dead 2 linux dedicated server' version 61

Checking/Installing 'Left 4 Dead 2 Add-on Support' version 6

HLDS installation up to date
CAsyncIOManager: 0 threads terminating.  0 reads, 0 writes, 0 deferrals.
CAsyncIOManager: 83 single object sleeps, 0 multi object sleeps
CAsyncIOManager: 0 single object alertable sleeps, 0 multi object alertable sleeps

AIRでAirRecord越しにSQLiteを使う

AIRでローカルDBのSQLiteを使う際に、直接使わずにO/Rマッパーを通して使ってみようということで、AirRecord を使ってみました。

Adobe Developer Connection の記事 を見ながらサンプルコードを書いてみました。

DBConfig.as

package  {
   public class DBConfig {
      /** ここに指定した文字列 + ".db" というファイル名でdbファイルが作成される。*/
      public static const DB_NAME:String = "myDB";

      /** .dbファイルを置くパス */
      public static const PATH:String = "app-storage:/";

      /** DB接続ユーザー名 */
      public static const USER:String = "hogehoge";

      /** DB接続に使用するパスワード */
      public static const PASSWORD:String = "hugahuga";

      /** 接続時に実行させるクエリ  配列要素順に実行 */
      public static const DDL:Array = [
         Bookmarks.DDL
      ];

      public function DBConfig() {
      }
   }
}

Bookmarks.as

package  {
   import jp.cre8system.framework.airrecord.model.ARModel;

   public class Bookmarks extends ARModel {
      /** 対応させるテーブル名 */
      public static const TABLE_NAME:String = "bookmarks";

      /** テーブル定義 */
      public static const DDL:String =
            "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" + 
            "   id         INTEGER PRIMARY KEY, " +
            "   name   TEXT, " + 
            "   url      TEXT" +
            ");";

      public var id:Number;
      public var name:String = "";
      public var url:String = "";

      public function Bookmarks() {
         super();
         this.__table = TABLE_NAME;   //テーブル名を渡す
      }
   }
}

AirRecordText.mxml

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
                  xmlns:s="library://ns.adobe.com/flex/spark" 
                  xmlns:mx="library://ns.adobe.com/flex/mx" 
                  creationComplete="init(event);" 
                  fontFamily="Meiryo, MS PGothic, Osaka" 
                  showStatusBar="false">
   <s:layout>
      <s:VerticalLayout verticalAlign="middle"/>
   </s:layout>

   <fx:Script>
      <![CDATA[
         import jp.cre8system.framework.airrecord.db.ARDatabase;
         import mx.collections.ArrayCollection;

         [Bindable]
         public var selectedData:ArrayCollection = null;   //SELECTしてきたデータの格納先

         private function init(event:Event):void {
            //DBへの接続
            var db:ARDatabase = ARDatabase.instance;
            db.add(
               DBConfig.USER, 
               DBConfig.PASSWORD, 
               DBConfig.DB_NAME, 
               DBConfig.DDL, 
               "",    //コネクション識別名
               DBConfig.PATH
            );
            db.connect();

            selectData();
         }

         //SELECTしてきてDataGridに渡す
         private function selectData():void {
            var bookmarks:Bookmarks = new Bookmarks();
            var result:Array = bookmarks.find(null, "id DESC");   //findメソッドでSELECTできる
            selectedData = new ArrayCollection(result);
         }

         //データ追加
         private function insertData(name:String, url:String):void {
            var bookmarks:Bookmarks = new Bookmarks();
            bookmarks.name = nameInput.text;
            bookmarks.url = urlInput.text;
            bookmarks.insert();
            //bookmarksのフィールドに代入してinsert()を呼ばずに
            //bookmarks.insert({name: nameInput.text, url:urlInput.text});
            //でもOK
         }

         //追加ボタンクリック時
         private function onClick(event:MouseEvent):void {
            if (nameInput.text == "" || urlInput.text == "") return;
            insertData(nameInput.text, urlInput.text);
            selectData();
         }
      ]]>
   </fx:Script>

   <s:HGroup width="100%" horizontalAlign="center" verticalAlign="middle">
      <s:Label text="サイト名" width="80" textAlign="right" paddingRight="5" />
      <s:TextInput id="nameInput" width="400"/>
   </s:HGroup>
   <s:HGroup width="100%" horizontalAlign="center" verticalAlign="middle">
      <s:Label text="URL" width="80" textAlign="right" paddingRight="5" />
      <s:TextInput id="urlInput" width="400"/>
   </s:HGroup>
   <s:HGroup width="100%" horizontalAlign="center" verticalAlign="middle">
      <mx:Spacer width="410" />
      <s:Button id="addButton" label="追加" click="onClick(event);" />
   </s:HGroup>

   <mx:Spacer width="100" height="50"/>

   <s:HGroup width="100%" horizontalAlign="center">
      <mx:Spacer width="30" />
      <mx:DataGrid width="450" dataProvider="{selectedData}">
         <mx:columns>
            <mx:DataGridColumn headerText="id" dataField="id" width="40"/>
            <mx:DataGridColumn headerText="name" dataField="name"/>
            <mx:DataGridColumn headerText="url" dataField="url"/>
         </mx:columns>
      </mx:DataGrid>
   </s:HGroup>

</s:WindowedApplication>

DB使ってるって気がしなくて楽ちんですね。