#Twitter のつぶやきを #Mastodon に流す,たとえWindowsしか使えなくても! #マストドン #初心者向け

やってみたけど意外に簡単だったのと,よく使う人もいそうなので超初心者向けメモ.

必要なもの

  • IFTTTに接続されたTwitterのアカウント
  • 適当なインスタンスのMastodonのアカウント(この場合,mstdn.io というインスタンスの o_ob というアカウント )
  • 最新のcurlが利用できるLinux等の環境もしくはWindows版curl

ネット上のドキュメントにはLinux環境でのドキュメントが多いので,Windows版curlでの説明で書いてみます.

なお「curl」とはコマンドラインで使えるブラウザのようなもので,curl http://… とすることでそのURLを叩くことができます.ダウンローダーなど嬉恥ずかしい使い方もたくさんあるのですが,今回はPOSTメソッドでMustodonのAPIを叩くのに使います.

ちなみにLinux環境で,curlが入っているけどなんかエラーが出る人は,最新のTLS対応でない可能性があります.管理者権限で yum update してください.

Macの人はターミナルに入っているはずです.

Windows版のcurlを入手する

curl.haxx.se/download.html

こちらで「Packages」の「Windows 64bit」の適当な圧縮形式のファイルを入手してください.
64ビット版の7.53.1はこちらにありました.例えばこのZIPをDownloadsにダウンロードして解凍した場合で,以下説明します.

バイナリファイル自体は Downloads\curl-7.53.1\src 」に curl.exe として入っていますが,これはコマンドライン用のEXEですのでダブルクリックしても何も起きません(見えない).

Windows+R で「ファイル名を指定して実行」→「cmd」でコマンドラインを開く.

2017-04-23 (1).png

黒こわい画面が開いたら,curl.exe をこの画面にドロップしてみましょう.

C:\Users\yourname>C:\Users\yourname\Downloads\curl-7.53.1\src\curl.exe

と出ていたら,エンターキーを軽快に叩いてみてください.

なんかメッセージが出たら,今度は curl.exe の後ろに「http://google.com」など適当なURLを打ち込んでみてください.

2017-04-23 (2).png

GoogleのトップページにアクセスしたときのHTMLが表示されます.まあ実際には「引越ししました,302エラー」が表示されています.

これで準備は終わりです,いろいろ細かいこともありますが,以下,このcurl.exe があるディレクトリで作業してしまいましょう.

まず独自アプリの登録

先ほどのディレクトリで curl(…curl.exe+半角スペース)に続いてコマンドを打っていきます.curl.exeをcurlと見なして以下真似てみてください(太字は変更).

curl -X POST -d “client_name=MSTDN2Twitter&redirect_uris=urn:ietf:wg:oauth:2.0:oob&scopes=write&website=https://aki.shirai.as” -Ss https://mstdn.io/api/v1/apps

なお,コマンドラインでは「↑」キーを押すと過去のコマンドを再利用することができます.マウスの右クリックでクリップボードに張り付けることもできます.

なお,client_nameは好きにつけられます,これから皆さんが作る独自アプリの名前ですのでせいぜいかっこいい名前にしましょう.websiteは自分のサイトでも大丈夫なはず,mstdn.ioは自分が利用したいインスタンスに置き換えてください.

うまくいくと以下のような文字列が出てきます.

{“id”:xxxx,”redirect_uri”:”urn:ietf:wg:oauth:2.0:oob”,”client_id”:”[A]64文字の英数字“,”client_secret”:”[B]64文字の英数字“}

マウスドラッグして変な改行や,テキストエディタなどに(Windows+Rで「notepad」)スペースが入らないようにして張り付けておきましょう.

アプリにユーザを登録する

次に,このアプリを使ってご使用のインスタンスでユーザID,パスワードを使って認証をし,トークン(Token)という専用回数券を入手します.

curl -X POST -d “scope=write&client_id=[A]&client_secret=[B]&grant_type=password&username=[メールアドレス]&password=[パスワード]” -Ss https://[mstdn.io]/oauth/token

  • [A]はひとつ前のプロセスで発行されたclient_id
  • [B]はひとつ前のプロセスで発行されたclient_secret
  • [メールアドレス]はご利用のMastodonサーバ(インスタンス)で登録したメールアドレス
  • [パスワード]はご利用のMastodonインスタンスで登録したパスワード
  • [mstdn.io]はご利用のMastodonインスタンスのURL本体に置き換えてください

[~]や”~”などのカッコや引用符はつける必要がありません.ドラッグと右クリックを使って丁寧に作業してください.正しく設定できているとエンターを押した後に,

{“access_token”:”[C:英数64文字のトークン]“,”token_type”:”bearer”,”scope”:”write”,”created_at”:[日付数字]}

という反応が出ます.これも大事な文字列なのでテキストエディタに拾っておきましょう.トークンは大事なものなので,ネットなどに撒くのは危険です!

間違っていた場合は以下のような文字列になります.メールアドレスやパスワードをよく確認してください,ちゃんとログインできますか?

<html><body>You are being <a href=”https://mstdn.io/auth/sign_in”>redirected</a>.</body></html>

どうしてもうまくいかないときは上記のcurl の後に続く「-Ss」(反応を表示しない)のところを「-v」(全部表示)にしてみるといろいろ分かるかもしれません.

 

試しにcurlから投稿してみる

さてせっかくですので試しにcurlから投稿してみましょう!

curl.exe -X POST -d “access_token=[C]&status=Hello World!&visibility=private” -Ss https://[mstdn.io]/api/v1/statuses

  • [C]はアクセストークンです.長い英数文字列です.引用符などは不要です.
  • Hello World!はつぶやきたい文字列です,日本語はここでは問題があります.
  • privateにしておくと,ほかの人には見えません.
  • [mstdn.io]はご使用のインスタンスに置き換えてください.カッコは不要です.

いかがでしょうか?うまく投稿されましたか?うまくいかなかった場合は「Oops.png」や「We’re sorry, but something went wrong.」といったHTMLが反応として返ってくるはずです.

IFTTTで自動化投稿設定をする

IFTTTについて細かく解説が必要な方は,ほかのサイトなども見てください.If [何か起きたら] then [何かする]というシンプルな部品の組み合わせで強力なWebサービスが作れます.個人利用や試作としては十分な機能を持っており,プログラミング不要です.

使用するモジュールは「maker_webhooks」です.

  • 名称は[My Twitter2Mastodon]など自由にどうぞ.
  • [New Tweets by You]:RTを対象にする,@返信を対象にする場合はそれぞれチェック.
  • [URL]:[https://mstdn.io/api/v1/statuses] お使いのインスタンスに合わせて変更してください
  • [Methods]:[POST]
  • [Content Type]:[application/x-www-form-urlencoded]
  • [Body]:[visibility=public&access_token=[Cのトークン]&status={{Text}}

 

{{Text}}の前後にはスペースを入れないことをお勧めします.「Ingredient」を使えばURLなども入ります.

Saveしたら適当なつぶやきをTwitter側でやってみて実験しましょう!(意味なくつぶやくのは意外と大変…)

うまくいかないときはIFTTTのApplet側のLogを確認しましょう.変なスペースが入ってたりすると事故の元です.

visibilityは{private, public, unlisted, direct}をとります.小文字で書くことに注意.

ちなみにIFTTTを使いこなしている人は,Wordpressの投稿をつないだり,出勤簿にしたりと,いろいろ使い道を思いつくはずです!

Happy Tweeting and Tooting!

 

おまけ1:作業の後片付けをしたい

はい,終わったらcurlのフォルダごと捨ててしまいましょう.

特に,Mastodonのパスワードやトークンがその辺に残っているのは気持ち悪いですので!

ここまで解説した方法の良いところは,コマンドライン上で操作していますので,パスワードを保存したりすることが一切ない点なのです.

 

おまけ2:Mastodon → Twitterもやりたい

ちなみに Mastodon→Twitter はできるけどあまり利点がないので検証してません.

簡単に言うと,Mastodonには標準でATOMを吐いてくれますので,それを拾えば既存の各種サービスでできることが多いからです.

具体的には,ご自身のアカウントの後ろに「.atom」を付けたURLにアクセスすれば,フィードが取れます.

mstdn.io/@o_ob.atom

以上です!

何か間違いやフィードバックがありましたら,こちらのTOOTまでどうぞ.

mstdn.io/@o_ob/815348

メディアアートを考えながら,オンライン年賀状、結局どこで出すのが得なのかを調べてみた

2017年新春,追記しました.

 

#年賀状はメディアアート」というタグを展開していることもあって年賀状はメディアアートではないかと考えている.


メディアアートの授業では「メディアアートとは人と人との関係性を作るアート」と定義してさまざまな作品を分析解説している.ここ数年は「郵便年賀.jp」というサイトがさまざまなWebクリエイターを巻き込み,大変興味深いメディアアートとしか呼びようがない作品(サービス)を展開されていたのであるが,今年は,全然新作がない.2015年末に株公開を達成し民営化の成功によるものだろうか.そら「干支似顔絵作成ツール」とかつくったら12年はイノベーションしなくても良いのかなという気もしないでもないが,そんなことをしているとメディアアートは社会に溶けて行くだけなので,新しいメディアアートを作り出さねばならない.

21世紀にハガキは絶滅するのか?

年賀状はよいものである.特にハガキがいい.丸見えなのも,良い.時間がかかるのも良い.SNSで「あけおめことよろ」なんてタイムラインを見ていなければ流れてしまうし,そんな手軽な挨拶は新年にふさわしくない.ハガキは丸見えでやってくる.家族にも親戚にも丸見えのソーシャリティ全開のアートだ.グラフィックアートが中心であるが,手芸や工芸,アニメ,マンガ,ゲームといったメディアアートの範疇に入るオタク文化もしっかりと受け止められる.なんならMaker文化も取り込んで電子回路も組み込んでもらってもいい.

しかし手紙という文化ははっきりいって廃れている.フランス人は旅行に行ったらまず最初に「絵葉書はどこだ,ポストはどこだ」といって家族や親戚に10枚ぐらいは出す.アメリカでも郵便局は街中のいいところにドカンとある.しかしメキシコに行ったら郵便局どころか切手もない,そもそもポストがない.空港ならさすがにあるだろうと思って聞いてみると,「クーリー?そんなものはクーリーエレクトリックで出せ」と言われた.メールは電子メールで出せ,か.そうだよね,この手に持っているスマホでパシャっと絵葉書とってメールで送ればいいよね….って違うだろ!だったら御土産物屋で絵葉書売るなよ!電子回路組み込むぞ!

もし自分が乗った飛行機が落ちたとする!メキシコで強盗にあって死んだとする!
そんな時,自分が最後に送った電子メールにどれだけの意味があるんだよ!
お葬式やるころに,届くであろう絵葉書がいいんじゃないか,わかってくれよ!

それはともかく,オンライン年賀状はよい

それはともかく,オンライン年賀状は良い.郵便年賀.jpが生み出したものの中で一番win-win-winなプロジェクトではないだろうか.ハガキ派も,ネット派も郵便局も儲かる.ハイブリッド感がよい.

なんといっても,翌年以降は住所とかを管理する必要がないのもうれしい.年末の寒くて忙しい時期にプリンター関係でイライラしなくて良いなら,数千円のコストは払うべきと思う.自分で印刷してもそれぐらいかかるし.

値段を調べてみた

ここ数年,郵便年賀.JPと提携していた「ウェブポ」と「Yahoo年賀状」を利用している.ウェブポはあまりが画質が良くなかった(レーザープリンタ画質)が,今年は富士フィルムイメージングの高品質印刷でまあまあ.Yahoo年賀状はスマホアプリで宛名を読み込める(ちょうど名刺管理サービスのEightに似ているクラウド人力処理)ので元旦以降に便利である.

(2017年追記)Yahoo年賀状は2017年はサービスしていないようで,株式会社connectitのこちらのサイトになります.
net-nengajo.jp/service/scan/

価格体系は変わらず以下のようです.

  通常価格 10-29枚
(10% OFF)
30-49枚
(20% OFF)
50枚以上
(30% OFF)
普通紙 78円 71円 63円 55円
写真用紙 108円 98円 87円 76円
喪中・寒中 68円 62円 55円 48円

 

価格については,初めての人にとっては年に一度しか使わないから,正直なところ,一度頼んでみないとよくわからないと思うだろうから,以下,グラフにしてみた.

maisu-kingaku

tanka

私はどちらかのサービスの回し者ではないし,安ければよいと言うことでもないからコメントはしないけれど,数枚ならどちらも大して変わらないが,30枚以降で変化があるので確認すべき.さらに,80枚頼むより,100枚で頼んだほうが合計金額からして安いということもある.日数やサイトの使いやすさなどは各サイトで確認して欲しい.それから自分はオリジナル画像を印刷するだけなので,デザインの豊富さとか,アーティストコラボ的な要素が好きな人はそれも大事かもしれない.

グラフの読み方がわからなかったり,追加情報があれば @o_ob までお寄せいただければ幸いです.
(宣伝とか商売とかは無視しますが)

 

 

Pebble Timeの直しかた – BluetoothLE不具合・ハードリセット編

Pebble Time
研究に使っているPebble Timeをとあるサイトで配布している日本語化pbzで日本語化したら,しばらく後に不具合.
日本語が直接関係あるかどうかわからなかったのですが,症状としては,
・iPhone経由で通知機能を使うためにBluetooth LE(BLE)で接続するとPebble Timeがフリーズ→再起動
・Android経由では再起動にならないが何かおかしい
Pebble初代から使ってきましたが,通知機能が使えないPebbleなんてただのカワイイ電子ペーパー玩具!もうこんな時計ごみ箱に捨ててやる!!と思ったのですが,その前にアプリからサポートに連絡する方法があるのでログを送信.
思ったよりも多くの情報を収集できるようで,またサポートインシデントもちゃんと立ってくれて,しかもほかの人も同様の問題をレポートしていたらしく,結構簡単に治っちゃいました.しかも日本語も使える.

Pebble公式で日本語サポートしてほしいと思いますので,同様の不具合がある人はどんどんレポートするといいとおもいますが,
自分で解決できそうですし,お急ぎの人もいると思いますので,以下,日本語訳しておきます.
(Pebbleの会社はとっても楽しそうなので日本語も楽しそうにしておきました)

<サポートのMubaさんからのメール>

やあ,Akihiko,
レポートありがとう!
こいつは,インストールした言語パックに問題がある可能性があるね.
この問題の繰り返しから回避するためには,英語に戻してあげる必要があります.

あなたは時計のファームウェアとBluetooth接続をリセットするには、以下の手順を使用することができます。
以下のステップで,時計のファームウェアとBluetooth接続をリセットできます.

1. 時計を充電器に置き,十分に充電されていることを確認します.
2. iPhone/Android本体のSetting>Bluetooth からPebbleとPebble LEをリストから探し,[i]を押してそのデバイスを削除(forget)します.
3. Pebble appをハードクローズします.(iPhoneの場合はホームボタンをダブルクリック,Androidの場合はアプリ切り替えを長押しして)アプリをスワイプして終了させます.
4. iPhoneを強制再起動します.ホームとロックボタンをリンゴロゴが出るまで5-10秒長押ししてください.
5. Pebbleの[左][右中][右上]を40秒長押しして,リカバリーモードに入ります.
6. これで,Settings > Bluetooth は,まだペアリングされていない状態になりますので,Pebble(Pebble LEではなく!)をiPhoneに接続できます.
7. 再度 Pebble appを開いてみてください.

最後に,通知設定の処理が残っていますので以下のリンクをご参照.
help.getpebble.com/customer/portal/articles/1191239-setting-up-ios-notifications
★要約すると,通知センターでアプリごとに「通知を許可」,「ロック画面に表示」,「バナー」を選んでください,ということですね.

ちゃんと治りましたよ!やった!BLEの通知機能も使えるようになりました.
これでゴミ箱に捨てずに済む!

しかも日本語もちゃんと使えるようになってました.
おそらく,古いファームウェアとの互換性でBLE関係の初期設定が上書きされてしまったとかそんな感じなんだろうな.

おまけ:Pebble創業者のインタビューをご紹介

サポートはPebbleにとっても重要なユーザとの絆です.
このBlogを読んだ人もまずはサポート機能を使ってみてくださいね.

ローソンポータルの効果

2014年11月15日。
Ingress2周年かつ相模原市立博物館でIngressを使った、ゲームを使ったゲーミフィケーション、市域全域を使ったフィールドミュージアムについての話をしている真っさなかに日本中のローソンがポータルになった。

とりあえず予想よりも早くNIAがIngressのマネタイズを開始したなあ、と思い少し残念な気持ちもあるけれど、これは産業応用、キャズム越えへのカウントダウンと言えるだろう。
次のDarsanaでニュースが扱い、大メディアが扱い、社会現象化し、高校生がハマり、「歩きスマホ、自転車や車の事故が増えたのはIngressのせいだ」とか言われるようになるまで先行者の利はそれほど残っていない。レベルも新参者に遠に追い抜かれた。

そんなわけでローソンポータルが萌えた今、感じていることを書き残しておく。

・管理する数が増えた
これは強者の占有を減らせるかもしれない
・固有ポータル固着する気も失せるだろう(Good)
・強度史跡系はより貴重になるだろう
・広告効果絶大
・リアル課金完成
・トイレ借りやすくてGood
・不審者、駐車問題解決
・過疎地問題ほぼ解決
・ローソンの出店計画とマッチ(一等地すぎないこと)
・街ナビとしての性能向上
・こんなところにローソンあったっけ?というほど見つかる
・よく考えたら普通のナビの地図上にはコンビニがユビキタス過ぎてブランド意識してない
・これは通勤経路変わるレベル
・っていうかオフィスから40mだけ動けばハックできるポータルが生えたので、これは休憩がてら行くキッカケに(普段はコンビニ弁当嫌いなので腹が減っても動かず仕事している)
・きっと次はファミマ(青と緑)
・「街のホットステーション」がホットなXMステーションに。

まだまだありそう。

IMG_5738.PNG

IMG_5737.PNG

IMG_5735.PNG

IMG_5736.PNG

Google APIをつかってみる(初歩の初歩編)

ふとしたことからYouTubeAPIを使う必要が出てきたので、Google APIを久々に触ってみる。

作りたいものはYouTubeで自分がアップロードした動画のリストなどを取得するC#.NETで開発したスタンドアロンアプリ。

一気に解説するのは大変そうなのと、このあたりを解説している日本語ページがまったくなかったで、まずは導入編から。

〔参考資料〕

Google APIs Client Library for .NET (本家)
developers.google.com/api-client-library/dotnet/get_started

書いてあるとおりで動くなら問題ないのだけど、動かないので。

ちなみに以下、開発環境はVisual Studio 2010です。

具体的にはスレッド周りのコードが動きません、たぶん.NETが古いからコンパイルできない。

www.atmarkit.co.jp/ait/articles/1109/30/news126.html

以下、実際に動いたソース。コンソールアプリの新規プロジェクト作成ウィザードからべたっとはりつけてしまっても動くはずです。

using System;
using Google.Apis.Discovery.v1;
using Google.Apis.Discovery.v1.Data;
using Google.Apis.Services;

namespace Discovery.ListAPIs
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            Console.WriteLine("Discovery API Sample");
            Console.WriteLine("====================");
            try
            {
//                new Program().Run().Wait();
                new Program().Run();
            }
            catch (AggregateException ex)
            {
                foreach (var e in ex.InnerExceptions)
                {
                    Console.WriteLine("ERROR: " + e.Message);
                }
            }
            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
        }

//        private async Task Run()
        private void Run()
        {
            // Create the service.
            var service = new DiscoveryService(new BaseClientService.Initializer
            {
                ApplicationName = "Discovery Sample"
                //,
                //                    APIKey = "[API Key]", //今回は必要ない
            });

            // Run the request.
            Console.WriteLine("Executing a list request...");
            //            var result = await service.Apis.List().ExecuteAsync();
            var result = service.Apis.List().ExecuteAsync();

            // Display the results.
            if (result.Result.Items != null)
            {
                foreach (DirectoryList.ItemsData api in result.Result.Items)
                {
                    Console.WriteLine(api.Id + " - " + api.Title);
                }
            }
        }
    }
}

コメントアウトしているところは、本家GoogleAPIのサイトでは非同期関数で実装しているところを、わかりやすく普通の関数で実装しなおしている部分です。

なお、ビルドを通すためにはNuGetを使って必要なライブラリを追加していく必要があります。
NuGetのVisual Studioへのインストールはこちらをご参考。
www.atmarkit.co.jp/fdotnet/chushin/nuget_01/nuget_01_01.html
NuGetで管理できるGoogle APIでどんなライブラリが存在するかはこちらのリンクがわかりやすいです。
NuGetでパッケージ管理できるGoogleAPI一覧

具体的にはNuGetのパッケージマネージャで、以下のコマンドを使ってパッケージをインストールします。

PM> Install-Package Google.Apis
PM> Install-Package Google.Apis.Tasks.v1
PM> Install-Package Google.Apis.Discovery.v1

無事ビルドがとおり、実行すると、利用できるGoogle APIの一覧が表示できます。

Discovery API Sample
====================
Executing a list request...
adexchangebuyer:v1 - Ad Exchange Buyer API
adexchangebuyer:v1.1 - Ad Exchange Buyer API
adexchangebuyer:v1.2 - Ad Exchange Buyer API
adexchangebuyer:v1.3 - Ad Exchange Buyer API
adexchangeseller:v1 - Ad Exchange Seller API
adexchangeseller:v1.1 - Ad Exchange Seller API
adexchangeseller:v2.0 - Ad Exchange Seller API
admin:directory_v1 - Admin Directory API
admin:email_migration_v2 - Email Migration API v2
admin:reports_v1 - Admin Reports API
adsense:v1.2 - AdSense Management API
adsense:v1.3 - AdSense Management API
adsense:v1.4 - AdSense Management API
adsensehost:v4.1 - AdSense Host API
analytics:v2.4 - Google Analytics API
analytics:v3 - Google Analytics API
androidpublisher:v1 - Google Play Android Developer API
androidpublisher:v1.1 - Google Play Android Developer API
androidpublisher:v2 - Google Play Android Developer API
appsactivity:v1 - Google Apps Activity API
appstate:v1 - Google App State API
audit:v1 - Enterprise Audit API
autoscaler:v1beta2 - Google Compute Engine Autoscaler API
bigquery:v2 - BigQuery API
blogger:v2 - Blogger API
blogger:v3 - Blogger API
books:v1 - Books API
calendar:v3 - Calendar API
civicinfo:us_v1 - Google Civic Information API
civicinfo:v1 - Google Civic Information API
civicinfo:v2 - Google Civic Information API
cloudmonitoring:v2beta1 - Cloud Monitoring API
compute:v1 - Compute Engine API
content:v2 - Content API for Shopping
coordinate:v1 - Google Maps Coordinate API
customsearch:v1 - CustomSearch API
datastore:v1beta1 - Google Cloud Datastore API
datastore:v1beta2 - Google Cloud Datastore API
dfareporting:v1 - DFA Reporting API
dfareporting:v1.1 - DFA Reporting API
dfareporting:v1.2 - DFA Reporting API
dfareporting:v1.3 - DFA Reporting API
discovery:v1 - APIs Discovery Service
dns:v1beta1 - Google Cloud DNS API
doubleclickbidmanager:v1 - DoubleClick Bid Manager API
doubleclicksearch:v2 - DoubleClick Search API
drive:v1 - Drive API
drive:v2 - Drive API
freebase:v1-sandbox - Freebase Search
freebase:v1sandbox - Freebase Search
freebase:v1 - Freebase Search
fusiontables:v1 - Fusion Tables API
games:v1 - Google Play Game Services API
gamesManagement:v1management - Google Play Game Services Management API
gan:v1beta1 - Google Affiliate Network API
genomics:v1beta - Genomics API
gmail:v1 - Gmail API
groupsmigration:v1 - Groups Migration API
groupssettings:v1 - Groups Settings API
identitytoolkit:v3 - Google Identity Toolkit API
licensing:v1 - Enterprise License Manager API
manager:v1beta2 - Deployment Manager API
mapsengine:exp2 - Google Maps Engine API
mapsengine:v1 - Google Maps Engine API
mirror:v1 - Google Mirror API
oauth2:v1 - Google OAuth2 API
oauth2:v2 - Google OAuth2 API
pagespeedonline:v1 - PageSpeed Insights API
plus:v1 - Google+ API
plusDomains:v1 - Google+ Domains API
prediction:v1.2 - Prediction API
prediction:v1.3 - Prediction API
prediction:v1.4 - Prediction API
prediction:v1.5 - Prediction API
prediction:v1.6 - Prediction API
pubsub:v1beta1 - Cloud Pub/Sub API
qpxExpress:v1 - QPX Express API
replicapool:v1beta1 - Replica Pool API
reseller:v1sandbox - Enterprise Apps Reseller API
reseller:v1 - Enterprise Apps Reseller API
resourceviews:v1beta1 - Resource Views API
resourceviews:v1beta2 - Resource Views API
siteVerification:v1 - Google Site Verification API
spectrum:v1explorer - Google Spectrum Database API
sqladmin:v1beta1 - Cloud SQL Administration API
sqladmin:v1beta3 - Cloud SQL Administration API
storage:v1 - Cloud Storage API
storage:v1beta1 - Cloud Storage API
storage:v1beta2 - Cloud Storage API
taskqueue:v1beta1 - TaskQueue API
taskqueue:v1beta2 - TaskQueue API
tasks:v1 - Tasks API
translate:v2 - Translate API
urlshortener:v1 - URL Shortener API
webfonts:v1 - Google Fonts Developer API
webmasters:v3 - Webmaster Tools API
youtube:v3 - YouTube Data API
youtubeAnalytics:v1 - YouTube Analytics API
youtubeAnalytics:v1beta1 - YouTube Analytics API
Press any key to continue...

さてこれでYouTube Data API v3.0が利用できますね。

このあたりはまた今度。

 

追記:プロジェクトはGithubでも公開しておきましたので、ご活用ください。

github.com/kaitas/ShiraiLabOpen/tree/master/GoogleAPIs/GoogleAPIsListing

 

AHO='() { baka; }; echo manuke’ bash -c ‘echo Hi’

「ほとんどすべてのLinuxに使用されているシェル”bash”にとんでもない脆弱性(CVE-2014-6271)があるのだそうだ」…と言っても,動く人はいないだろう.

お手近なLinuxにログインできる人は 以下のコマンドを打ってみてほしい.

 AHO='() { baka; }; echo manuke' bash -c 'echo Hi'

「Hi」と出ず「manuke」と出れば,未対策.なお管理者権限は必要ない,ユーザで確認できる.

環境変数に任意のコマンドを突っ込んで実行できるということを示しているのだけど,

アホだの間抜けだの言われながらのほうが緊急性が刺激されることはよくわかった.

あなたが管理者なら

# yum list installed | grep bash

して該当のバージョン以降(bash-4.1.2-15.el6_5.1など)になっていることを確認しよう.なおパッチはbash3.x系にも配布されているし,ShellShock攻撃として実際に利用する被害が出始めているので,とにかく急いで対応すべし.

yumで管理しているなら,

# yum -y update bash

これ一発で終わる.

 

参考:bashの脆弱性がヤバすぎる件

x86-64.jp/blog/CVE-2014-6271

 

Twitter Digestを改造した

WordPressがTwitterのStatusURLを入れると,見やすい展開をはかってくれるようになったのに,
Twitter Digestは相変わらずリストでしか表示してくれないし,画像は展開してくれないので,以下のような魔改造を施しました.akiで検索してみてください.
あんまり重たいようだったらやめよう.

それにしてもどうして,定期まとめツイートが走らなかったんだろう…?しばらく様子見.

Twitter account.

Version: 2.9
Author: Tim Beck
Author URI: http://whalespine.org
*/

// Copyright (c) 2009 - 2010 Tim Beck and Paul Wlodarczyk. All rights reserved.
//
// Released under the GPL license
// http://www.opensource.org/licenses/gpl-license.php
//
// This is an add-on for WordPress
// http://wordpress.org/
//
// **********************************************************************
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// **********************************************************************
//
//=======================
// Defines

define('WS_FETCH_SPACE', 30); //X seconds between fetches
define('WS_TWITTER_LIMIT', 200); //the most tweets you can pull from the Twitter REST API
define('WS_API_USER_TIMELINE', 'https://api.twitter.com/1.1/statuses/user_timeline.json');
define('WS_STATUS_URL', 'https://twitter.com/###USERNAME###/statuses/###STATUS###');
define('WS_PROFILE_URL', 'https://twitter.com/###USERNAME###');
define('WS_HASHTAG_URL', 'https://twitter.com/search?q=###HASHTAG###&src=hash');
define('WS_VERSION', '2.9');

//========================
// Digest cron activation

register_activation_hook(__FILE__, 'ws_activate_digest');
register_deactivation_hook(__FILE__, 'ws_deactivate_digest');
add_action('ws_td_digest_event', 'ws_ping_twitter');

function ws_activate_digest() {
wp_schedule_event(time(), 'hourly', 'ws_td_digest_event');
}

function ws_deactivate_digest() {
wp_clear_scheduled_hook('ws_td_digest_event');
}

// Check Twitter to see if there are any new tweets that need to be published.
// Return values:
// null -> all good
// 1 -> Error w/ twitter
// 2 -> Too soon
// 3 -> Missing username/password
// 4 -> Post created and published now or put in draft (depending on status option)
// 5 -> No tweets to post
// 6 -> Post created but not published until later
// 7 -> Wrong day of week

function ws_ping_twitter() {

// Do we have a username?
if (!get_option("ws_td_username")) {
return 3;
}

// We don't need the password anymore, so delete it.
if (get_option("ws_td_password")) {
delete_option("ws_td_password");
}

// Has there been enough time since the last check? This avoids a race
// condition which would produce a duplicate post.

$last = get_option('ws_td_last_check');
if (time() - $last < WS_FETCH_SPACE) { return 2; } update_option("ws_td_last_check", time()); // Is this a daily or weekly post? // Need to know today's local midnight to work out start/end times $midnight = strtotime(date('Y-m-d, 00:00:00', time() + ws_gmtOffset())); $pub_day = get_option('ws_td_pub_day'); $pub_freq = get_option('ws_td_freq'); $current_day_of_week = date("w", $midnight); // Test if it's weekly, then if so is today the right day of the week. If // not, return; pub_freq=0 is daily if ($pub_freq == 1) { if ($current_day_of_week != $pub_day) { return 7; } else { // 7 days ago at midnight $startDate = strtotime('-7 days', $midnight); } } else { // yesterday at midnight $startDate = strtotime('-1 days', $midnight); // $startDate = strtotime('-15 days', $midnight); } // yesterday at 11:59:59 $endDate = strtotime('-1 second', $midnight); $startDateStr = date(ws_getDateFormat(), $startDate); $endDateStr = date(ws_getDateFormat(), $endDate); // Get the last tweet id from the last post $lastTweet = get_option('ws_td_last_tweet'); if (!$lastTweet) { $lastTweet = 0; update_option('ws_td_last_tweet', $lastTweet); } // Get the tweets $numtweets = get_option('ws_td_num_tweets'); // range check. Twitter limit is to 200 if ($numtweets > WS_TWITTER_LIMIT) {
$numtweets = WS_TWITTER_LIMIT;
}

if ($numtweets == 0) {
$numtweets = 20; //default is 20 with no count argument, so fetch 20 if NULL
}

// get the last N tweets, since the last tweet
$url = WS_API_USER_TIMELINE . "?screen_name=".get_option('ws_td_username') ."&count=". $numtweets ;

if (get_option('ws_td_includeRTs')) {
$url .= '&include_rts=1';
}

if ($lastTweet) {
$url .= "&since_id=" . $lastTweet;
}

// Fetch the tweets
$tweets = ws_fetch_tweets($url);

// Go through the array and process any tweets from the desired time period
$tweet_content = array();
$tweet_ids = array(); //aki
$newLastTweet = false;
if ($tweets && count($tweets) >= 0) {
// process the tweets

foreach ($tweets as $tw_data) {
// Convert the time to local
$tw_data->created_at = strtotime($tw_data->created_at) + ws_gmtOffset();

// Was this tweet added in the time period of interest?
if ($tw_data->created_at < $startDate) { continue; } if ($tw_data->created_at > $endDate ) {
continue;
}

// Are we dropping replies?
if (get_option('ws_td_drop_replies') && preg_match('/^@.*/', $tw_data->text)) {
continue;
}

// All good, so format and add to the content
array_push($tweet_content, ws_format_tweet($tw_data)."\n\n");
array_push($tweet_ids, ws_format_tweet_id($tw_data)); //aki

// Remember the first tweet in the list, which is actually the most
// recently tweeted.
if (!$newLastTweet) {
$newLastTweet = $tw_data->id_str;
}
}

// To avoid race conditions, check to make sure lastTweet hasn't changed
if ($lastTweet == get_option('ws_td_last_tweet')) {

$count = count($tweet_content);

if ($count != 0 && $count >= get_option('ws_td_min_tweets')) {

// Before we push the content, we need to put it in the right order
if (get_option('ws_td_chrono') == 1) {
$tweet_content = array_reverse($tweet_content);
$tweet_ids = array_reverse($tweet_ids); //aki
}

$title = get_option('ws_td_title');
if (!$title) {
$title = "Tweets for %startdate";
}

// We look for %date to be backwards compatible
$title = preg_replace("/%date/", $startDateStr, $title);
$title = preg_replace("/%startdate/", $startDateStr, $title);
$title = preg_replace("/%enddate/", $endDateStr, $title);

$excerpt = get_option('ws_td_excerpt');
$excerpt = preg_replace("/%date/", $startDateStr, $excerpt);
$excerpt = preg_replace("/%startdate/", $startDateStr, $excerpt);
$excerpt = preg_replace("/%enddate/", $endDateStr, $excerpt);

//aki start
$postcontent = join("\n", $tweet_ids);
$postcontent .= "\n\n

    \n\n";
    //aki end
    //aki $postcontent .= "

      \n\n";
      $postcontent .= join("\n\n", $tweet_content);
      $postcontent .= "\n

    ";

    // This is messy, but good enough for now.
    if (ws_create_post($postcontent, $title, get_option('ws_td_pub_time'), $excerpt)
    == 1 /* Published in future */) {
    $retval = 6;
    } else {
    // Published now or drafted.
    $retval = 4;
    }

    // Update the last tweet id
    update_option('ws_td_last_tweet', $newLastTweet);

    return $retval;

    }
    else {
    return 5;
    }
    }

    }
    else {
    return 5;
    }

    }

    // This function creates the actual post and schedules it for publishing time
    // at $pubtime, if the status option is set to 'publish'. Otherwise the post
    // is put in 'draft' status.
    // Return values:
    // 0: published now
    // 1: published in future
    // 2: drafted
    function ws_create_post($content, $title, $pubtime, $excerpt) {

    global $wpdb;
    $result = 0;

    // Are we putting this in draft or publishing (now or later)?
    if (get_option('ws_td_status') == 'draft') {
    $status = 'draft';
    $result = 2;
    } else {

    $status='publish';

    // Are we doing this now or later?
    if ($pubtime) {
    $time = date('Y-m-d ').$pubtime.":00";
    $timestamp = strtotime($time);
    if ($timestamp > current_time('timestamp')) {
    $result = 1;
    }
    } else {
    $time = current_time('mysql');
    }
    }

    // Create the post
    $post_data = array(
    'post_content' => $wpdb->escape($content),
    'post_title' => $wpdb->escape($title),
    'post_date' => $time,
    'post_category' => array(get_option('ws_td_category')),
    'post_status' => $status,
    'post_author' => $wpdb->escape(get_option('ws_td_author')),
    'post_excerpt' => $wpdb->escape($excerpt)
    );

    // Insert post
    $post_id = wp_insert_post($post_data);
    add_post_meta($post_id, 'ws_tweeted', '1', true);

    // Tag it
    wp_set_post_tags($post_id, get_option('ws_td_post_tags'));

    return $result;
    }
    // customized by aki 2014/3/26
    function ws_format_tweet_id($tweet) {
    $output = ws_status_url(get_option('ws_td_username'), $tweet->id_str);
    return $output;
    }

    // Returns an html formatted $tweet. This is almost directly borrowed from Twitter Tools
    function ws_format_tweet($tweet) {
    $output = '

  • ';
    $output .= ws_make_clickable(wp_specialchars($tweet->text));
    if (!empty($tweet->in_reply_to_screen_name)
    && (!empty($tweet->in_reply_to_status_id))) {
    $output .= ' '.sprintf(__('in reply to %s', 'twitter-digest'), $tweet->in_reply_to_screen_name).'';
    }

    // Show the date/time if the options are selected
    $showTime = get_option('ws_td_showtime');
    if (!$showTime) { $showTime = 0; }
    // Show the date if the option is selectd
    $showDate = get_option('ws_td_showdate');
    if (!$showDate) { $showDate = 0; }

    $time_display = '';
    if ($showTime == 1) {
    $time_display = gmdate('H:i:s', $tweet->created_at);

    // Add the comma if we are going to show the date as well
    if ($showDate == 1) {
    $time_display .= ", ";
    }
    }

    // Add the date
    if ($showDate == 1) {
    $time_display .= gmdate('Y-m-d', $tweet->created_at);
    }

    // Use a small arrow for the status links if time and date are off
    if ($showDate != 1 && $showTime != 1) {
    $time_display = "->";
    }

    // Add the status link
    $username = get_option('ws_td_username');
    $output .= ' '.$time_display.'';

    $output .= '

  • ';
    return $output;

    }

    // Most of the following formatting functions are borrowed from Twitter Tool
    function ws_make_clickable($tweet) {

    // $tweet = preg_replace('/\@([a-zA-Z0-9_]{1,15}) /','@\\1 ', $tweet);
    $tweet = preg_replace_callback(
    '/((?:^|\s+|[\"\'\[\(]))\@([\w]{1,30})/',
    create_function(
    '$matches',
    'return $matches[1].ws_profile_link($matches[2]);'
    ),
    $tweet
    );
    $tweet = preg_replace_callback(
    '/((?:^|\s+|[\"\'\[\(]))\#([\w]{1,30})/',
    create_function(
    '$matches',
    'return $matches[1].ws_hashtag_link($matches[2]);'
    ),
    $tweet
    );

    // make_clickable doesn't handle (url) very well, so we'll chuck some spaces in
    $tweet = preg_replace("/\((http.*)\)/", "( $1 )", $tweet);

    return make_clickable($tweet);
    }

    function ws_status_url($username, $status) {
    return str_replace(
    array('###USERNAME###', '###STATUS###'),
    array($username, $status),
    WS_STATUS_URL);
    }

    function ws_profile_link($username, $prefix = '@') {
    return ''.$prefix.$username.'';
    }

    function ws_hashtag_link($hashtag, $prefix = '#') {
    return ''.$prefix.htmlspecialchars($hashtag).'';
    }

    function ws_profile_url($username) {
    return str_replace('###USERNAME###', $username, WS_PROFILE_URL);
    }

    function ws_hashtag_url($hashtag) {
    $hashtag = urlencode('#'.$hashtag);
    return str_replace('###HASHTAG###', $hashtag, WS_HASHTAG_URL);
    }

    // Based on Alex King's implementation for the Twitter Tools plugin
    function ws_fetch_tweets($url) {

    // First get our oauth connection
    require_once("twitteroauth.php");
    $consumerkey = get_option('ws_td_conskey'); // "3JucGrvAxOuaAYbLml5nkQ";
    $consumersecret = get_option('ws_td_conssecret'); //"iIRXb7c0VFwTYmI4TCNNIrUWB2YDxmL6c11YogcqQw0";
    $accesstoken = get_option('ws_td_acctoken'); // "14198382-SnzuP0AMz3qVWTolneB8QG7D1kHt6WNMosZzb48LE";
    $accesstokensecret = get_option('ws_td_accsecret'); // "9O7sc2tbea8PEx3Py9S4VWsHkbZtDBcP0n4HvnzokqM";

    if (!$consumerkey || !$consumersecret || !$accesstoken || !$accesstokensecret) {
    update_option('ws_td_error', 'Check your account information and make sure all token fields have a valid value.');
    return false;
    }

    $connection = new TwitterOAuth($consumerkey, $consumersecret,
    $accesstoken, $accesstokensecret);

    // Now make the request
    $tweets = $connection->get($url);

    // Check the error code
    if(empty($connection->http_code) || $connection->http_code != 200) {
    update_option('ws_td_error', 'Error retrieving tweets.
    Status: '.$connection->http_code.' Check your authentication tokens.
    '.print_r($connection->http_info, true));
    return false;
    }

    // Everything is ok
    update_option('ws_td_error','');

    return $tweets;
    }

    // Simply resets the 'ws_td_last_tweet' option
    function ws_td_resetDatabase() {
    update_option('ws_td_last_tweet',0);
    }

    // The menu hook
    function ws_menu_item() {
    if (current_user_can('manage_options')) {
    add_options_page(
    __('Twitter Digest Options', 'twitter-digest')
    , __('Twitter Digest', 'twitter-digest')
    , 'manage_options'
    , basename(__FILE__)
    , 'ws_options_form'
    );
    }
    }
    add_action('admin_menu', 'ws_menu_item');

    function ws_options_form() {

    // Check here if we are going to do the check now
    global $wpdb;

    // Reset the database if necessary
    if (isset($_POST["action"]) && $_POST["action"] == 'resetdb') {
    ws_td_resetDatabase();
    }

    // Get some variables together
    $ping_message = "(This may take a while if there are tweets to process.)";
    $ping_style="color: black";

    // Range check the publish day
    $pub_day_value = get_option('ws_td_pub_day');
    if ($pub_day_value < 0 || $pub_day_value > 6) { $pub_day_value = date("w"); }

    // yesterday or last week?
    if (get_option('ws_td_freq') == 0) {
    $periodStr = 'yesterday';
    } else {
    $periodStr = 'last week';
    }

    // Ping if necessary, and show the correct message.
    if (isset($_POST["action"]) && $_POST["action"] == "ping") {
    switch(ws_ping_twitter(true)) {
    case 1:
    $pwuser = get_option('ws_td_username');

    $ping_message = "Something went wrong with Twitter. Check for an error message above. Current Twitter username is " . $pwuser. "." ;
    $ping_style = "color: red";
    break;
    case 2:
    $ping_message = "To keep things sane, we're going to wait ".WS_FETCH_SPACE." seconds between pings.";
    $ping_style = "color: red";
    break;
    case 3:
    $ping_message = "Missing Twitter username and/or password";
    $ping_style = "color: red";
    break;
    case 4:
    $ping_message = "Post containing ".$periodStr."'s tweets has been ".(get_option('ws_td_status'). 'ed.');
    $ping_style ="color: green";
    break;
    case 6: $ping_message = "Post containing ".$periodStr ."'s tweets scheduled.";
    $ping_style = "color: green";
    break;
    case 5: $ping_message = "No new tweets found from " . $periodStr;
    break;
    case 7:
    $daylabel = date("l");
    $pub_day_str = ws_getDoW($pub_day_value);
    $now = date("H:i:s");
    $pub_time_str = get_option('ws_td_pub_time');
    if (!$pub_time_str) { $pub_time_str = '00:00:00'; }

    $ping_message = "Today is " . $daylabel . " and the local time is " . $now . " and you are configured to publish on " . $pub_day_str . " at " . $pub_time_str . ".";
    $ping_style = "color: red";
    }
    }

    // Get all the options together
    $categories = get_categories('hide_empty=0');
    $cat_options = '';
    foreach ($categories as $category) {
    if ($category->term_id == get_option('ws_td_category')) {
    $selected = 'selected="selected"';
    }
    else {
    $selected = '';
    }
    $cat_options .= "\n\t";
    }

    // get_users_of_blog is deprecated.
    $authors = get_users_of_blog();
    $author_options = '';
    foreach ($authors as $user) {
    $usero = new WP_User($user->user_id);
    $author = $usero->data;
    // Only list users who are allowed to publish
    if (! $usero->has_cap('publish_posts')) {
    continue;
    }
    if ($author->ID == get_option('ws_td_author')) {
    $selected = 'selected="selected"';
    }
    else {
    $selected = '';
    }
    $author_options .= "\n\t";
    }

    // Set up the options for the status. Just draft or publish for now.
    $status_options = '';
    if (get_option('ws_td_status') == 'draft') {
    $status_options ='';
    } else {
    $status_options ='';
    }

    // Drop replies options
    $drop_replies_check = get_option('ws_td_drop_replies') == 1 ? 'checked="true"' : '';
    // Chrono options
    $chrono_check = get_option('ws_td_chrono') == 1 ? 'checked="true"' : '';
    // Show date options
    $showDate_check = get_option('ws_td_showdate') == 1 ? 'checked="true"' : '';
    $showTime_check = get_option('ws_td_showtime') == 1 ? 'checked="true"' : '';
    $includeRTs_check = get_option('ws_td_includeRTs') == 1 ? 'checked="true"' : '';

    // Publishing frequency options
    if (get_option('ws_td_freq') == 1) {
    $freq_options = '';

    $pub_day_display = '';
    } else {
    $freq_options = '';
    $pub_day_display = 'display: none';
    }

    // DoW option
    $pub_day_options = '';
    for ($i = 0; $i < 7; $i++) { $pub_day_options .= '

    // Default the min tweet value to 1
    $min_tweets_value = get_option('ws_td_min_tweets');
    if ($min_tweets_value < 1) { $min_tweets_value = 1; } // Default the number of tweets to 20 $num_tweets_value = get_option('ws_td_num_tweets'); if (!$num_tweets_value) { $num_tweets_value = 20; } print('

    '.__('Twitter Digest Options', 'twitter-tools').'

    '.ws_getErrorMessage().'


    '.wp_nonce_field('update-options').'


    Twitter Account Info






    Publish Options




    '._('Specify the time at which the tweet post should be published in 24 hour format e.g. 2:22pm = 14:22 or leave empty for ASAP').'

    '._('Specify the day of the week the post should be published in number format (0-6). e.g. Sunday = 0').'

    Post Options



    '._('Use %startdate and %enddate to insert the date').'


    '._('Use %startdate and %enddate to insert the dates').'


    '._('Defaults to Y-m-d').'



    '._('Separate multiple tags with commas. Example: tweets, twitter').'











    '.$ping_message.'



    Clicking this button resets the Twitter Digest database and may result in duplicate posts.

    ');
    }

    // Get the date option or fall back to the default
    function ws_getDateFormat() {
    $format = get_option('ws_td_dateFormat');
    if ($format == '') {
    $format = 'Y-m-d';
    }
    return $format;
    }

    // Get the string rep of a day given the index. Sunday = 0;
    function ws_getDoW($num) {
    switch($num) {
    case 0:
    return "Sunday";
    break;
    case 1:
    return "Monday";
    break;
    case 2:
    return "Tuesday";
    break;
    case 3:
    return "Wednesday";
    break;
    case 4:
    return "Thursday";
    break;
    case 5:
    return "Friday";
    break;
    case 6:
    return "Saturday";
    }

    }

    // Returns the gmt offset for WordPress in seconds
    function ws_gmtOffset() {
    return get_option('gmt_offset') * 3600;
    }

    function ws_gmtTime() {
    return time() - date("Z");
    }

    function ws_getErrorMessage() {
    $error = get_option('ws_td_error');
    if ($error) {
    return '

    '.$error.'

    ';
    }
    }

    define('MYPLUGIN_FOLDER', dirname(__FILE__));

Nexus7で物理キーボードを使う

「タブレットなんて、ビューワーにしかならん!」

と奥さんによく言われます。その通りだと思います。

その通りだと思うのですが、やはり可搬性やiPad,Androidの進化を考えると無視できない。

何とかモノ書き業に使いたい!
何とか生産的な作業に使いたい!
でないとこの板はただのオモチャにしかならないじゃないか!!

というわけで、前回の「文章を書くためのツール考―パソコン編―」に引き続き、スマートフォンをモノ書きに使うための検討を続けています。
今回はキーボード編です。
最近はPC選ぶのもキーボードが中心になってきましたし。
(Mac Book Airに勝てるキーボードはASUSやAcer、Lenovoしか出してません…現状)

Bluetoothキーボードはいろいろ試しているのですが、
ハードなフルキーボードはほとんど出ていません。
昔ながらのPS2キーボードなどを愛好する私としては、ちょっとしたアイテムを追加してみました。

ELECOM「U2HS-MB02-4SBK」、というmicroUSBをふつうのUSBに変換するポートです。

ELECOM USBHUB2.0 スマホ・タブレット用 microUSBケーブル+変換アダプタ付 バスパワー 4ポート ブラック U2HS-MB02-4BBK
microUSBからふつうのUSBに変換するコネクタもついて、近所の量販店で1000円以下でした。

これをNexus7に刺して、さらに無線マウスとPS2/USB変換につながったPS2キーボードを指します。
マウスはなんの問題もなくつながります。右クリックとホイールが超快適。そしてホームボタンなどもクリックできますので画面を触る必要がない。

肝心のキーボードのほうは…ちょっと設定があります。
メールなどはタブをうまく使うとよいでしょう。
日本語の文章入力では、Jotaなどで試していますが、うまく切り替わらない。

いろいろ試してみましたが、無料でできる一番簡単な方法は、
・Google日本語入力に切り替える
・Ctrl+Spaceで日本語切り替え
いちど日本語切り替えすると、以後は半角全角キーで切り替えられます。画面下に表示されるのも便利。
画面下のソフトキーボードが邪魔になるIMEもあるのですが、
おそらく、ですが、Google日本語入力は物理キーボードモードが用意されているようです。

さてこうなると、Bluetoothでもいいキーボードが出てほしくなりますね。

それってモバイルじゃないんじゃね?と言われそうですが。

HDMIに接続するだけのAndroid製品も出てきていますので、お気に入りのキーボードやマウスとAndroid鍵だけで環境が持ち歩けるという、
昔でいうところのNCよりもスマートなコンピューティング環境ができつつあります。

あとはプログラミング環境がほしくなりますね~。

継続使用してみて脱PCできるかどうか、試してみたいと思います。

Nexus 7にiPhone4SのSIMを刺す

softbankのiPhone4SをSIM Free版Nexus 7を刺してみた。
(当方iPhoneユーザにつきAndroidは詳しくありません。2013/2/27現在の情報)
結論から行くとこんな感じ。
・サイズはmicroSIMなので全く加工をしなくても入る。
・APNの設定をしなくても認識される
・APNの設定をすると、3G接続できる
 設定→無線とネットワーク→(その他)→モバイルネットワーク→アクセスポイント名
 SIMを一回抜くと消えてしまうようだ。
・電話が着信しても、かけたほうには呼び出し音が鳴るが、Nexus 7は何とも言わない。
 通話アプリを入れたらいいのかもしれないが、とりあえず見つからないのでいい方法があれば教えてください。
・残念ながらテザリングはできない。

海外でMicroSIMを入手したくなってきた…。

ちなみにAPNの情報、softbankの場合は以下。
APN smile.world
ユーザ名 dna1trop
パスワード so2t3k3m2a
ほかのキャリアは
www.gevey.com/apn
とかなんとか。

書籍「Google Apps Script クイックリファレンス」は大変心強い!

「Google Apps Script クイックリファレンス」(横山隆司・秀和システム刊)という書籍が2013年2月に発刊されているようなので入手しました。

国内初の本格的なGASのリファレンスブックです。いわゆる「逆引きGoogle Apps Script」とでもいうべき書籍ですね。

www.shuwasystem.co.jp/products/7980html/3675.html

ものすごくボリュームがあります。507ページ!

特に興味深いのは、以下の項目ですね…。Googleの公式APIドキュメントには記載がありますが、学生さんに読んでもらって分かりそうな「具体的なサンプル」は滅多に存在しませんので…。

  • 5-4 開始時間と終了時間を指定してイベントを追加するには
  • 6-14 ダッシュボードを作成するには
  • 6-17 文字列フィルタを作成するには
  • 7-12 連絡先から取得/設定できる値は
  • 8-1 テキストコンテンツを出力するには
  • 10-8 ドキュメントの末尾にリストのアイテムを追加するには
  • 10-9 ドキュメントの末尾に表を追加するには
  • 12-34 Gmailのメールから取得できる値は
  • 14-2 HTML文字列を出力するには
  • 15-1 文字列を翻訳するには
  • 17-2 1日に送信できるメールのクォータを取得するには
  • 18-21 座標から住所の情報を取得するには
  • 21-3 ScriptDbにデータを保存するには
  • 22-8 サイトにファイルキャビネットページを追加するには
  • 24-49 セルを結合するには
  • 25-9 UiInstanceを使って生成できるウィジェットは
  • 25-14 DatePickerを利用するには
  • 25-15 DateBoxを利用するには
  • 26-1 外部サイトのURLにアクセスするには
  • 26-2 OAuth設定を取得するには
  • 26-3 OAuth設定に設定する値は
  • 26-4 HTTPResponseから取得できる値は
  • 27-1 書式文字列を指定して日付を文字列に変換するには
  • 27-2 JSON文字列をオブジェクトに変換するには
  • 27-3 オブジェクトをJSON文字列に変換するには
  • 27-4 Blobオブジェクトを作成するには
  • 28-1 XML文字列を解析するには
  • 29-2 キャッシュにデータを保存するには
  • 29-3 キャッシュに保存されているデータを取り出すには
  • 30-1 Google Cloud SQLを利用するには
  • 31-2 Google Apps ScriptでBigQueryを利用するには

Google Apps Scriptクイックリファレンス

以下、公式から引用した目次です。

Chapter 1 Google Apps Scriptの概要
1-1 Google Appsとは
1-2 Google Apps Scriptとは
1-3 Google Apps Scriptでできることは
1-4 Google SpreadSheetでスクリプトを作成するには
1-5 Google Siteでスクリプトを作成するには
1-6 Google Apps Script単体プロジェクトを作成するには
Chapter 2 スクリプトエディタ
2-1 スクリプトを作成するには
2-2 スクリプトを実行するには
2-3 スクリプトの実行ログを表示するには
2-4 スクリプトをデバッグ実行するには
2-5 ブレークポイントを設定するには
2-6 作成したスクリプトをデバッグするには
2-7 スクリプトエディタで補完機能を利用するには
2-8 スクリプトエディタでプロジェクトのプロパティを編集するには
2-9 スクリプトの変更履歴を表示するには
2-10 開発したプロジェクトのスナップショットを取るには
2-11 作成したプロジェクトのプログラムをライブラリとして利用するには
2-12 ライブラリプロジェクトにコメントを反映させるには
2-13 ライブラリプロジェクトのドキュメントを見るには
Chapter 3 トリガー
3-1 トリガーとは
3-2 特定の日時にトリガーを起動するには
3-3 定期的に実行するトリガーを登録するには
3-4 スプレッドシートを開いた時に実行するトリガーを設定するには
3-5 スプレッドシートの保存時に実行するトリガーを設定するには
3-6 スプレッドシートのフォームから登録された時に実行するトリガーを設定するには
Chapter 4 Baseサービス
4-1 実行ログを出力するには
4-2 実行ログをクリアするには
4-3 現在の実行ログを取得するには
4-4 ダイアログボックスを表示するには
4-5 入力ボックスを表示するには
4-6 ログインしているユーザを取得するには
4-7 スクリプトを実行しているユーザを取得するには
4-8 スクリプトのタイムゾーンを取得するには
4-9 ユーザのメールアドレスを取得するには
4-10 ユーザのログインIDを取得するには
Chapter 5 Calendar
5-1 任意の日に終日のイベントを登録するには
5-2 任意の日に終日の拡張オプション付きイベントを追加するには
5-3 定期的な終日のイベントを追加するには
5-4 開始時間と終了時間を指定してイベントを追加するには
5-5 タイトル文字列からのquick-add機能を利用するには
5-6 開始時間と終了時間を指定した定期的なイベントを追加するには
5-7 カレンダーを作成するには
5-8 Google Calendarに設定したすべてのカレンダーを取得するには
5-9 Google Calendarに設定したすべてのマイカレンダーを取得するには
5-10 カレンダーの名前を指定してGoogle Calendarに設定したカレンダーを取得するには
5-11 IDを指定してGoogle Calendarに設定したカレンダーを取得するには
5-12 カレンダーの名前を指定してGoogle Calendarに設定したマイカレンダーのカレンダーを取得するには
5-13 カレンダーのIDを指定してGoogle Calendarに設定したマイカレンダーのカレンダーを取得するには
5-14 プライマリカレンダーを取得するには
5-15 繰り返しイベントのルールを作るには
5-16 Google Calendarに登録されているカレンダーの予定を取得するには
5-17 カレンダーに設定している色を取得するには
5-18 カレンダーの説明を取得するには
5-19 カレンダーを削除するには
5-20 終日のイベントを取得するには
5-21 IDを指定して、定期的なイベントを取得するには
5-22 カレンダーのIDを取得するには
5-23 カレンダーの名前を取得するには
5-24 カレンダーのタイムゾーンを取得するには
5-25 カレンダー設定の「リストに表示」にチェックがあるかどうかを確認するには
5-26 カレンダーがプライマリカレンダーかどうかを確認するには
5-27 カレンダーの所有者が現在のアカウントかどうかを確認するには
5-28 カレンダーの表示状態を確認するには
5-29 カレンダーの色を設定するには
5-30 カレンダーの詳細説明を設定するには
5-31 カレンダーの「リストに表示」設定を変更するには
5-32 カレンダーの名前を設定するには
5-33 カレンダーの表示状態を設定するには
5-34 カレンダーのタイムゾーンを設定するには
5-35 定期的なイベントで1日毎の繰り返し設定を作成するには
5-36 定期的なイベントで指定した回数分登録されるのを除外するには
5-37 定期的なイベントの終了日を指定するには
5-38 定期的なイベントで特定の日付には登録されないようにするには
5-39 定期的なイベントで1ヶ月毎の繰り返し設定を作成するには
5-40 定期的なイベントで1ヶ月毎の繰り返し設定を指定した回数分除外するには
5-41 定期的なイベントで1週間毎の繰り返し設定を作成するには
5-42 定期的なイベントで1週間毎の繰り返し設定を指定した回数分除外するには
5-43 定期的なイベントで1年毎の繰り返し設定を作成するには
5-44 定期的なイベントで1年毎の繰り返し設定を指定した回数分除外するには
5-45 イベントの詳細情報を取得、設定するには
5-46 定期的なイベントの詳細情報を取得、設定するには
5-47 イベントを削除するには
Chapter 6 Charts
6-1 データテーブルを作成するには
6-2 面グラフを作成するには
6-3 棒グラフを作成するには
6-4 横向きの棒グラフを作成するには
6-5 折れ線グラフを作成するには
6-6 円グラフを作成するには
6-7 散布図を作成するには
6-8 表を作成するには
6-9 グラフの表示を変更するには
6-10 グラフの表示サイズを変更するには
6-11 折れ線グラフをなめらかな曲線で表示するには
6-12 円グラフを3D表示にするには
6-13 テキストのスタイルを生成するには
6-14 ダッシュボードを作成するには
6-15 数値の範囲フィルタを作成するには
6-16 カテゴリフィルタを作成するには
6-17 文字列フィルタを作成するには
6-18 グラフのカラムを表示するかどうかを制御するには
Chapter 7 Contacts
7-1 連絡先を作成するには
7-2 連絡先グループを作成するには
7-3 連絡先を取得するには
7-4 連絡先を削除するには
7-5 すべての連絡先を取得するには
7-6 連絡先にメールアドレスを追加するには
7-7 連絡先に電話番号を追加するには
7-8 連絡先にインスタントメッセンジャーのアカウントを追加するには
7-9 連絡先にURLを追加するには
7-10 連絡先に勤務先を追加するには
7-11 連絡先に誕生日を追加するには
7-12 連絡先から取得/設定できる値は
Chapter 8 Content
8-1 テキストコンテンツを出力するには
8-2 テキストコンテンツに文字列を追加するには
8-3 テキストコンテンツに追加した文字列をクリアするには
8-4 テキストコンテンツをファイルとしてダウンロードさせるには
8-5 テキストコンテンツに文字列を設定するには
8-6 テキストコンテンツのMimeTypeを設定するには
8-7 TextOutputから取得できる値は
8-8 設定できるMimeTypeは
Chapter 9 DocsList
9-1 ファイルを作成するには
9-2 フォルダを作成するには
9-3 ファイルを取得するには
9-4 フォルダを取得するには
9-5 ファイルを検索するには
9-6 ファイルの共同編集者を追加するには
9-7 ファイルの閲覧者を追加するには
9-8 ファイルの共同編集者を削除するには
9-9 ファイルの閲覧者を削除するには
9-10 ファイルのコピーを作成するには
9-11 ファイル名を変更するには
9-12 ファイルの詳細情報を取得するには
9-13 ファイルに文字列を追加するには
9-14 ファイルに追加した文字列をクリアするには
9-15 ファイルの中身を置き換えるには
Chapter 10 Document
10-1 ドキュメントを作成するには
10-2 IDを指定してドキュメントを取得するには
10-3 アクティブなドキュメントを取得するには
10-4 ドキュメントにフッターを追加するには
10-5 ドキュメントにヘッダーを追加するには
10-6 ドキュメントの末尾に区切り線を追加するには
10-7 ドキュメントの末尾に段落を追加するには
10-8 ドキュメントの末尾にリストのアイテムを追加するには
10-9 ドキュメントの末尾に表を追加するには
10-10 ドキュメントの末尾に改ページを追加するには
10-11 ドキュメントの末尾に画像を追加するには
10-12 ドキュメントに区切り線を挿入するには
10-13 ドキュメントに段落を挿入するには
10-14 ドキュメントにリストのアイテムを挿入するには
10-15 ドキュメントに表を挿入するには
10-16 ドキュメントに改ページを挿入するには
10-17 ドキュメントに画像を挿入するには
10-18 ドキュメントの編集内容を保存するには
10-19 ドキュメントのテキストオブジェクトを取得するには
10-20 ドキュメントの本文を置換するには
10-21 ドキュメントの各種情報を取得、設定するには
10-22 ヘッダーを細かく編集するには
10-23 フッターを細かく編集するには
10-24 段落を細かく編集するには
10-25 画像を細かく編集するには
10-26 テキストを細かく編集するには
Chapter 11 Finance
11-1 株価の履歴を取得するには
11-2 株価情報の詳細を取得するには
11-3 取引データの詳細を取得するには
Chapter 12 Gmail
12-1 ラベルを作成するには
12-2 ラベル名を指定してラベルを取得するには
12-3 全てのラベルを取得するには
12-4 ラベルを削除するには
12-5 チャットの履歴を取得するには
12-6 Gmailの受信トレイのメールを取得するには
12-7 Gmailの受信トレイにある重要なメールを取得するには
12-8 Gmailのスター付きメールを取得するには
12-9 Gmailの迷惑メールを取得するには
12-10 Gmailのゴミ箱にあるメールを取得するには
12-11 Gmailのメールのスレッドを取得するには
12-12 GmailのメールIDからメールを取得するには
12-13 Gmailのメールを既読にするには
12-14 Gmailのメールを未読にするには
12-15 Gmailのスレッドを既読にするには
12-16 Gmailのスレッドを未読にするには
12-17 Gmailのスレッドを重要なスレッドにするには
12-18 Gmailのスレッドを普通のスレッドにするには
12-19 Gmailのメールをゴミ箱に移動するには
12-20 Gmailのスレッドをアーカイブ化するには
12-21 GmailのスレッドをSpamに設定するには
12-22 Gmailのスレッドを受信トレイに移動するには
12-23 Gmailのメールをリフレッシュするには
12-24 Gmailメールを検索するには
12-25 Gmailのメールをスター付きにするには
12-26 Gmailのスター付きメールのスターを外すには
12-27 Gmailのメールの件数を取得するには
12-28 Gmailのラベルにスレッドを追加するには
12-29 Gmailのラベル内のスレッドを取得するには
12-30 Gmailのラベルからスレッドを削除するには
12-31 Gmailのラベルから取得できる値は
12-32 Gmailのスレッドのメールに返信するには
12-33 Gmailのスレッドから取得できる値は
12-34 Gmailのメールから取得できる値は
12-35 Gmailのメールを転送するには
Chapter 13 Group
13-1 ログインしているユーザが所属しているGoogle Groupを取得するには
13-2 Google Groupのメールアドレスからグループを取得するには
13-3 Google Groupから取得できる値は
Chapter 14 HTML
14-1 htmlファイルを作成するには
14-2 HTML文字列を出力するには
14-3 HTML出力にコンテンツを追加するには
14-4 HtmlOutputでタイトルを設定するには
14-5 HtmlOutputのコンテンツをクリアするには
14-6 HtmlOutputで取得、設定できる値は
14-7 HTMLテンプレートを作成するには
14-8 HTMLテンプレートからHTML出力を生成するには
14-9 HTMLテンプレートから出力されるJavaScriptコードを取得するには
14-10 HTMLテンプレートに設定したコンテンツをそのまま取得するには
Chapter 15 Language
15-1 文字列を翻訳するには
Chapter 16 Lock
16-1 ユーザのみ有効なでプライベートロックを取得するには
16-2 すべてのユーザで有効なパブリックロックを取得するには
16-3 ロックを取得するには
16-4 ロックを解放するには
16-5 ロックを取得しているかどうかを確認するには
Chapter 17 Mail
17-1 メールを送信するには
17-2 1日に送信できるメールのクォータを取得するには
Chapter 18 Maps
18-1 静的なマップオブジェクトを取得するには
18-2 特定の住所のマップオブジェクトを取得するには
18-3 特定の住所にマーカーをセットするには
18-4 地図の中に直線を引くには
18-5 地図に表示する直線の定義を開始するには
18-6 直線の頂点を追加するには
18-7 地図に表示する直線の定義を終了するには
18-8 設定したマーカーをクリアするには
18-9 設定した直線をクリアするには
18-10 地図の中心を設定するには
18-11 表示されるマーカーにカスタムスタイルを適用するには
18-12 地図の画像フォーマットを設定するには
18-13 地図の言語を設定するには
18-14 地図の種類を変更するには
18-15 地図に表示されるマーカーを変更するには
18-16 モバイル向けの地図を出力するには
18-17 直線のスタイルを設定するには
18-18 地図のサイズを設定するには
18-19 地図を拡大縮小するには
18-20 住所からGeocodeを取得するには
18-21 座標から住所の情報を取得するには
18-22 Geocodeの言語を指定するには
18-23 Geocodeのリージョンを指定するには
18-24 2点間のルートを計算するには
18-25 指定した場所の高度データを取得するには
Chapter 19 Properties
19-1 スクリプトのプロパティにキーをセットするには
19-2 スクリプトのプロパティに複数のキーを一括でプロパティを設定するには
19-3 スクリプトのプロパティを取得するには
19-4 スクリプトのプロパティを一括で取得するには
19-5 スクリプトのプロパティのキーの一覧を取得するには
19-6 スクリプトのプロパティを削除するには
19-7 スクリプトのプロパティを全て削除するには
19-8 ユーザプロパティにキーをセットするには
19-9 ユーザプロパティに複数のキーを一括でセットするには
19-10 ユーザプロパティを取得するには
19-11 ユーザプロパティを一括で取得するには
19-12 ユーザプロパティのキーの一覧を取得するには
19-13 ユーザプロパティを削除するには
19-14 ユーザプロパティを全て削除するには
Chapter 20 Script
20-1 トリガーオブジェクトを生成するには
20-2 登録されているトリガーの一覧を取得するには
20-3 登録されているトリガーを削除するには
20-4 登録されているサービスを取得するには
20-5 承認を解除するには
20-6 SpreadSheet用トリガー作成オブジェクトを生成するには
20-7 時間主導型トリガー作成オブジェクトを生成するには
20-8 時間主導型トリガーに毎日起動することを指定するには
20-9 時間主導型トリガーに毎時間起動することを指定するには
20-10 時間主導型トリガーに毎分起動することを指定するには
20-11 時間主導型トリガーに毎週起動することを指定するには
20-12 時間主導型トリガーに毎月何日に起動することを指定するには
20-13 時間主導型トリガーに「何時に実行するか」を指定するには
20-14 時間主導型トリガーに特定の日時を指定するには
20-15 時間主導型トリガーに細かい起動時間(分)を指定するには
20-16 時間主導型トリガーにタイムゾーンを指定するには
20-17 時間主導型トリガーを登録するには
Chapter 21 ScriptDb
21-1 ScriptDbとは
21-2 ScriptDbにアクセスするためのインスタンスを取得するには
21-3 ScriptDbにデータを保存するには
21-4 ScriptDbに複数のデータを一気に保存するには
21-5 ScriptDbからデータを取得するには
21-6 特定の検索条件を指定して、ScriptDbからデータを取得するには
21-7 ScriptDbに保存したデータを削除するには
21-8 ScriptDbに保存したデータを一括で削除するには
21-9 ScriptDbに保存したデータのIDを指定して削除するには
21-10 ScriptDbに保存したデータのIDを指定して一括で削除するには
21-11 特定の検索条件を指定して、ScriptDbに保存されているデータ件数を取得するには
21-12 一括更新時に全ての処理が成功したかどうかを確認するには
21-13 ScriptDbからデータを取得するクエリの条件指定の仕方は
21-14 ScriptDbから取得したデータをソートするには
21-15 クエリの取得結果の件数の上限を指定するには
21-16 クエリの取得結果の開始位置を指定するには
21-17 クエリの取得結果をページ指定で取得するには
21-18 クエリの取得結果の件数を取得するには
21-19 クエリの取得結果から、データを1件取得するには
21-20 クエリの取得結果で、次のデータがあるかどうかを確認するには
21-21 キーの読み出しやクエリで取得したデータをJSON形式の文字列で出力するには
21-22 キーの読み出しやクエリで取得したデータのIDを取得するには
21-23 キーの読み出しやクエリで取得したデータのプロパティを参照するには
Chapter 22 Sites
22-1 Google Siteにサイトを作成するには
22-2 サイトを取得するには
22-3 URLを指定してサイトを取得するには
22-4 作成したサイトを一括で取得するには
22-5 アクティブなSiteを取得するには
22-6 アクティブなPageを取得するには
22-7 サイトにアナウンス用ページを追加するには
22-8 サイトにファイルキャビネットページを追加するには
22-9 サイトにリストページを追加するには
22-10 サイトにWebページを追加するには
22-11 サイトの共同編集者を追加するには
22-12 サイトのオーナーを追加するには
22-13 サイトの閲覧者を追加するには
22-14 サイトの共同編集者を削除するには
22-15 サイトのオーナーを削除するには
22-16 サイトの閲覧者を削除するには
22-17 サイトのページを検索するには
22-18 サイトから取得できる情報は
22-19 リストページのリストに列を追加するには
22-20 ページにコメントを追加するには
22-21 ページに添付ファイルを追加するには
22-22 リストページのリストに行を追加するには
22-23 ファイルキャビネットページのリストにリンクを追加するには
22-24 アナウンスページにアナウンスを追加するには
22-25 テンプレートページを作成するには
22-26 テンプレートからページを作成するには
22-27 ページを削除するには
22-28 ページから取得できる情報は
22-29 コメントを削除するには
22-30 コメントから取得できる値は
22-31 リストページの行から取得できる値は
22-32 リストページの列から取得できる値は
22-33 添付ファイルを削除するには
22-34 ページの添付ファイルから取得できる値は
22-35 ページの種類と添付ファイルの種類は
Chapter 23 SOAP
23-1 WSDLファイルを取得するには
23-2 WSDLのサービス名を取得するには
23-3 WSDLServiceから取得できる値は
Chapter 24 Spreadsheet
24-1 アクティブなスプレッドシートを取得するには
24-2 アクティブなシートを取得するには
24-3 アクティブなRangeを取得するには
24-4 スプレッドシートを開くには
24-5 スプレッドシートを作成するには
24-6 スプレッドシートに対する変更を適用するには
24-7 スプレッドシートに共同編集者を追加するには
24-8 スプレッドシートに閲覧者を追加するには
24-9 スプレッドシートにカスタムメニューを追加するには
24-10 スプレッドシートに追加したカスタムメニューを削除するには
24-11 アクティブなシートに行のデータを追加するには
24-12 アクティブなシートを削除するには
24-13 アクティブなシートをコピーするには
24-14 シートを追加するには
24-15 アクティブなシートを移動させるには
24-16 スプレッドシートの共同編集者を削除するには
24-17 スプレッドシートの閲覧者を削除するには
24-18 スプレッドシートにカスタムUIのダイアログを表示させるには
24-19 スプレッドシートに通知ウインドウを表示させるには
24-20 シートの最下行にデータを追加するには
24-21 シートの値、書式を全てクリアするには
24-22 シートのコメントを削除するには
24-23 シートの全てのセルの値を削除するには
24-24 シートの全てのセルの書式を削除するには
24-25 シートを他のスプレッドシートにコピーするには
24-26 シートの列を削除するには
24-27 シートの行を削除するには
24-28 シートの行を隠すには
24-29 シートの列を隠すには
24-30 シートにグラフを追加するには
24-31 シートのグラフを削除するには
24-32 シートに行を挿入するには
24-33 シートに列を挿入するには
24-34 シートに画像を追加するには
24-35 非表示にした列を表示させるには
24-36 非表示にした行を表示させるには
24-37 セルの値を並び替えるには
24-38 Spreadsheetから取得できる値は
24-39 Sheetから取得できる値は
24-40 範囲を選択するには
24-41 結合したセルを分割するには
24-42 特定範囲の値、書式を全てクリアするには
24-43 特定範囲のコメントを削除するには
24-44 特定範囲のセルの値を削除するには
24-45 特定範囲のセルの書式を削除するには
24-46 特定範囲のセルの書式をコピーするには
24-47 特定範囲のセルの値をコピーするには
24-48 特定範囲のセル(値、書式全て)をコピーするには
24-49 セルを結合するには
24-50 セルの値を移動するには
24-51 指定範囲をオフセットを指定して変更するには
24-52 Range内のセルの値をソートするには
24-53 Rangeから取得できる値は
24-54 シートの保護を行うには
24-55 シートの保護中に編集可能なユーザを追加するには
24-56 シートの保護中に編集可能なユーザを削除するには
24-57 シートの保護中に編集可能なユーザを取得するには
24-58 シートが保護されているかどうかを取得するには
24-59 グラフを作成するときに範囲を指定するには
24-60 グラフで指定した範囲を削除するには
24-61 グラフのオプションを設定するには
24-62 グラフの種類を指定するには
24-63 グラフの表示位置を指定するには
24-64 グラフオブジェクトを作成するには
24-65 作成したグラフオブジェクトを編集するには
24-66 作成したグラフから取得できる値は
24-67 グラフの詳細情報から取得できる値は
Chapter 25 Ui
25-1 Google Apps ScriptでUIを利用するには
25-2 UIを構成するためのインスタンスを生成するには
25-3 生成したUiInstanceを取得するには
25-4 UIを画面に追加するには
25-5 ウィジェットにタイトルを設定するには
25-6 UiInstanceに設定できる値は
25-7 GUI Builderで作成したUIをロードするには
25-8 ウィジェットのIDを指定してオブジェクトを取得するには
25-9 UiInstanceを使って生成できるウィジェットは
25-10 アンカーを利用するには
25-11 ボタンを利用するには
25-12 キャプション付きパネルを利用するには
25-13 チェックボックスを利用するには
25-14 DatePickerを利用するには
25-15 DateBoxを利用するには
25-16 サーバ側で動作するイベントハンドラを利用するには
25-17 クライアント側で動作するイベントハンドラを生成するには
25-18 メニューを利用するには
25-19 タブを利用するには
25-20 SubmitButtonを利用するには
Chapter 26 UrlFetch
26-1 外部サイトのURLにアクセスするには
26-2 OAuth設定を取得するには
26-3 OAuth設定に設定する値は
26-4 HTTPResponseから取得できる値は
Chapter 27 Utilities
27-1 書式文字列を指定して日付を文字列に変換するには
27-2 JSON文字列をオブジェクトに変換するには
27-3 オブジェクトをJSON文字列に変換するには
27-4 Blobオブジェクトを作成するには
27-5 スクリプトの実行中にSleepさせるには
Chapter 28 Xml
28-1 XML文字列を解析するには
28-2 XML要素を生成するには
28-3 XML属性を生成するには
28-4 XmlAttributeから取得できる値は
28-5 XmlElementからXML文字列を出力するには
28-6 XmlElementから取得できる値は
28-7 XmlDocumentからXML文字列を出力するには
28-8 XmlDocumentの最上位の要素を取得するには
28-9 XmlNameから取得できる値は
Chapter 29 Cache
29-1 キャッシュを取得するには
29-2 キャッシュにデータを保存するには
29-3 キャッシュに保存されているデータを取り出すには
29-4 キャッシュに保存されているデータを削除するには
Chapter 30 JDBC
30-1 Google Cloud SQLを利用するには
30-2 データベースに接続するには
30-3 接続をクローズするには
30-4 AutoCommitを制御するには
30-5 Statementを生成するには
30-6 PreparedStatementを生成するには
30-7 select文を実行するには
30-8 PreparedStatementのプレースホルダーに値を設定するには
30-9 select文の結果を1行取得するには
30-10 select文の結果の列の値を取得するには
30-11 更新系SQL文を実行するには
30-12 行数を返さないSQL文を実行するには
30-13 実行するSQL文をバッチ登録するには
30-14 登録された複数のSQL文をバッチ実行させるには
30-15 データベースへの変更をコミットするには
30-16 データベースへの変更をロールバックするには
30-17 Statementをクローズするには
30-18 プレースホルダーに設定するための特殊なオブジェクトを生成するには
Chapter 31 BigQuery
31-1 BigQueryとは
31-2 Google Apps ScriptでBigQueryを利用するには
31-3 BigQueryのクエリの書き方は
31-4 BigQueryで実行するクエリで使える関数は
31-5 BigQueryでクエリを実行するには
31-6 BigQueryで実行しているクエリの終了を確認するには
31-7 BigQueryのテーブルのデータを取得するには
31-8 テーブルやクエリの実行結果から行データを取得するには
31-9 取得した行データから列のデータを取得するには
31-10 BigQueryに行を追加するには
A Appendix
A-1 Google Apps Scriptに関する参考資料について
A-2 外部JavaScriptライブラリをGoogle Apps Scriptに取り込む

おわりに

欲を言えば25章のUIで、ファイルアップロードについても解説していただければよかったかな、と。

でも使える情報が多くて助かります。突破力のあるコードを書かねばならないときに、見通しが出る書籍があるのは大変心強いです。
■Google Apps Scriptクイックリファレンス