`
jake0719
  • 浏览: 90372 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

JACL中文文档

    博客分类:
  • Java
阅读更多

<!----><!----><!----><!----><!---->

博主注: 最近要写WAS的wsadmin脚本和JACL脚本,要参考文档,网上jacl的中文资料不多,找了下自己以前的收藏,居然有这么好的东东。现在拿出来分享下。简单介绍下:JACL(Java Command Language)是Tcl 脚本语言的 Java 实现。它是一个开源项目,用户遵循GNU LGP许可。它的在线英文文档地址是http://jacl.sourceforge.net/

http://publib.boulder.ibm.com/infocenter/wasinfo/v6r0/topic/com.ibm.websphere.express.doc/info/exp/ae/rxml_slinks.html 。可以去http://tcljava.sourceforge.net/docs/website/download.html下载jacl。

本文具体转载自哪里已经不得而知,望译者见谅!

Jacl

Jacl TCL 的一个备用实现,它是完全使用 Java 代码编写的。

wsadmin 工具使用 Jacl V1.3.1

基本语法:

Jacl 命令的基本语法如下:

Command    



arg1   



arg2   



arg3   



...

命令可以是一个内置命令名,也可以是一个 Jacl 过程。例如:

puts stdout {Hello, world!} 
=> Hello, world!

在此示例中,命令是 puts ,它有两个参数、一个 I/O 流标识和一个字符串。 puts 命令将字符串与尾随的新行字符一起写入 I/O 流。参数由命令解释。在该示例中, stdout 用于标识标准输出流。将 stdout 用作名称是由 puts 命令和其他 I/O 命令使用的约定。 stderr 识别标准错误输出,而 stdin 识别标准输入。

变量

set 命令将值指定给变量。此命令有两个参数:变量的名称和值。变量名可以是任何长度,且区分大小写。使用 Jacl 变量前无须声明它们。解释器将在第一次指定值时创建变量。例如:

set a 5
=> 5
set b $a
=> 5

第二个示例将变量 a 的值指定给变量 b 。使用美元标记( $)表明变量替换。您可以使用 unset 命令删除变量,例如:

unset varName1 varName2 ...

您可以将任何数量的变量传递到 unset 命令。如果尚未定义变量, unset 命令将报错。您可以使用 unset 命令删除整个数组或只删除单个数组元素。在数组上使用 unset 命令是清除大数据结构的简便方式。可以用 info exists 命令测试变量是否存在。因为 incr 参数首先要求变量存在,所以可能必须测试变量是否存在,例如:

if ![info exists foobar] {set foobar 0} else {incr foobar}

命令替换:

替换的第二种格式是命令替换。嵌套命令由方括号( [ ] )分隔。 Jacl 解释器对方括号中的所有内容求值,并将其作为一条命令求值。例如:

set len [string length foobar]
=> 6

在此示例中,嵌套命令如下: string length foobar string 命令对字符串执行各种操作。在这种情况下,命令要求字符串 foobar 的长度。单个命令中有几种命令替换情况,解释器从左括号至右括号处理它们。例如:

set number "1 2 3 4" 
=> 1 2 3 4
set one [lindex $number 0]
=> 1
set end [lindex $number end]
=> 4 
set another {123  



456  



789}           



=> 123  



456  



789
set stringLen [string length [lindex  



$another  



1]]
=> 3
set listLen [llength [lindex $another 1]
=> 1

数学表达式:

Jacl 解释器不对数学表达式求值。使用 expr 命令对数学表达式求值。 expr 命令的实现采用所有参数,将它们并置到一个字符串中,并将该字符串作为数学表达式进行语法分析。 expr 命令计算答案后,它格式化到字符串中并返回。例如:

expr 7.2 / 3
=> 2.4

反斜杠替换:

Jacl 解释器执行的最后一个替换类型是反斜杠替换。使用它来引用对解释器有特殊含义的字符。例如,如果要指定美元标记、花括号或括号字符,您可以用反斜杠来对它 进行引用。如果您正在使用许多反斜杠,那么您可以代之以使用花括号将内容分组,以关闭特殊字符的所有解释。有几种必需反斜杠的情况。例如:

set dollar "This is a string \$contain dollar char"
=> This is a string $contain dollar char 
 
set x $dollar
=> This is a string $contain dollar char 
 
set  



group {$ {} [] { [ } ]}
=> $ {} [] { [ } ]

您还可以使用反斜杠将长命令在多个行上继续。没有反斜杠的新行将终止命令。作为一行中最后字符的反斜杠将转换为空格。例如:

set  



totalLength  



[expr  



[string  



length  



"first string"] + \
[string  



length  



"second string"]]
=> 25

用花括号和双引号分组:

使用双引号和花括号将字分组在一起。引号允许组中发生替换,而花括号阻止替换。此规则适用于命令、变量和反斜杠替换。例如:

set s Hello
=> Hello
 
puts stdout "The length of $s is [string length $s]."
=> The length of Hello is 5.
 
puts  



stdout  



{The length of $s is [string  



length  



$s].}
=> The length of $s is [string length $s].

在第二个示例中, Jacl 解释器从 puts 命令在第二个参数上执行变量和命令替换。在第三个命令中阻止替换,因此字符串按原样打印。

因为 Jacl 语言使用反斜杠字符( \)作为转义字符,所以还必须特别注意路径描述。要修正此问题,可在分布式路径语句中用正斜杠来替换每个反斜杠,或使用两个反斜杠。例如: C:/ C:\\

过程和作用域:

Jacl 使用 proc 命令定义过程。定义过程的基本语法如下:

proc  



name  



arglist  



body

第一个参数是正在定义的过程的名称。该名称是区分大小写的,实际上它可以包含任何字符。过程名称和变量名不会相互冲突。第二个参数是过程的参数列表。第三个参数是条命令,或更通常是形成过程主体的一组命令。一旦定义 Jacl 过程,它将与任何内置命令一样使用。例如:

proc divide {x y} {
set result [expr $x/$y]
puts $result
}

在脚本中,这是调用 devide 过程的方式:

divide 20 5

它会给出类似以下的结果:

4

在此示例中并非真正必须使用变量 c。该过程主体也可写为:

return  



[expr  



sqrt($a  



*  



$a  



+  



$b  



*  



$b)]

此示例中的 return 命令是可选的,因为 Jacl 解释器将主体中最后一条命令值作为过程值返回。因此,该过程主体可以减少为:

expr  



sqrt($a  



*  



$a  



+  



$b  



*  



$b)

该过程结果是主体中最后一条命令返回的结果。 return 命令可用于返回特定值。

过程名称中存在单个、全局作用域。您可以在另一个过程中定义过程,但是在任何位置都可以看到它。变量和过程有不同的名称空 间,因此您的过程和变量可以有同一名称而不会有冲突。每个过程都有变量的本地作用域。过程中引入的变量仅在过程调用期间存在。过程返回后,取消定义那些变 量。如果外部作用域中存在同一变量名,那么使用过程中的变量名不会对它产生影响。过程外部定义的变量对于过程不可视,除非使用了全局作用域命令。

  • global 命令 全局作用域是顶级作用域。此作用域在任何过程外。必须通过使用 global 命令使变量在可以访问过程中命令的全局作用域中定义。 global 命令的语法如下:
global  



varName1  



varName2 ...

注释

使用井号字符( #)进行注释。

命令行参数

Jacl shell 将命令行参数作为 argv 变量的值传递到脚本。命令行参数数由 argc 变量提供。程序或脚本的名称不是 argv 的一部分,也不会由 argc 计数。 argv 变量是个列表。使用 lindex 命令从参数列表抽取项,例如:

set  



first  



[lindex  



$argv  



0]
set  



second  



[lindex  



$argv  



1]

字符串和模式匹配

字符串是 Jacl 语言中的基本数据项。您有多条命令可用于处理字符串。 string 命令的一般语法如下:

string operation stringvalue otherargs

operation 参数确定字符串的操作。第二个参数是字符串值。根据操作,可能还有其他参数。

下表包含 string 命令的摘要:

命令

描述

string compare str1 str2

按字典顺序比较字符串。如果相等则返回 0,如果 str1 排在 str2 前则返回 -1,其他情况则返回 1

string first str1 str2

返回 str1 第一次出现在 str2 中的索引,如果未找到 str1,那么返回 -1

string index string index

返回指定索引的字符。

string last str1 str2

返回 str1 最后一次出现在 str2 中的索引,如果未找到 str1,那么返回 -1

string length string

返回字符串中的字符数。

string match pattern str

如果 str 匹配模式,那么返回 1,否则返回 0

string range str i j

返回从 i j str 的字符范围

string tolower string

以小写字母返回字符串。

string toupper string

以大写字母返回字符串。

string trim string ?chars?

从字符串两端修剪 chars 中的字符。 chars 缺省为空格。

string trimleft string ?chars?

从字符串开头修剪 chars 中的字符。 chars 缺省为空格。

string trimright string ?chars?

从字符串末尾修剪 chars 中的字符。 chars 缺省为空格。

string wordend str ix

返回字符的 str 中的索引,该字符在包含索引 ix 的字符的字后。

string wordstart str ix

返回第一个字符的 str 中的索引,该字符在包含索引 ix 的字符的字中。

append 命令

append 命令的第一个参数是变量名。它将剩余的参数并置到命名变量的当前值。例如:

set  



foo  



z
=> z
 
append  



foo a b c
=> zabc

regexp 命令

regexp 命令提供对正则表达式匹配器的直接访问。语法如下:

regexp  



?flags?  



pattern  



string  



?match  



sub1  



sub2  



...?

如果字符串的一部分与模式匹配,那么返回值是 1 。否则,返回值将为 0 。模式不必匹配整个字符串。如果您需要更多控制,那么可以将 ^ 放在模式开头,从而将模式固定到字符串开头,或者可以将美元标记 $ 放在模式末尾,从而将模式固定在字符串末尾。您可以通过使用这两个字符强制模式匹配整个字符串。例如:

set  



text1  



"This is the first string"
=> This is the first string
 
regexp  



"first string" $text1
=> 1
 
regexp "second string"  



$text1
=>  



0

Jacl 数据结构

Jacl 语言中的基本数据结构是字符串。其中存在两种更高级别的数据结构:列表和数组。列表作为字符串来实现,而结构由字符串的语法定义。语法规则与命令相同。命 令是列表的特殊实例。数组是有索引的变量。索引是字符串值,因此您可以将数组看作是从一个字符串(索引)到另一个字符串(数组元素值)的映射。

Jacl 列表

Jacl 语言的列表是有特殊解释的字符串。在 Jacl 语言中,列表与命令有同一结构。列表是字符串,具有以空格分隔的列表元素。您可以使用花括号或引号将具有空格的字一起分组到一个列表元素中。

下表包含有关列表的命令:

命令

描述

list arg1 arg2

用列表的所有参数来创建它。

lindex list i

返回列表的第 i 个元素。

llength list

返回列表中的元素数。

lrange list i j

返回列表的第 i 到第 j 个元素。

lappend listVar arg arg ...

将元素追加到 listVar 的值

linsert list index arg arg ...

将元素插入到列表中位置索引的元素前。返回一个新的列表。

lreplace list i j arg arg ...

args 替换列表中的元素 i j。返回一个新的列表。

lsearch mode list value

返回根据方式匹配值的列表中元素的索引,分别是 -exact -glob -regexp -glob 是缺省值。如果未找到,那么返回 -1

lsort switches list

根据以下开关符对列表的元素进行排序: -ascii -integer -real -increasing -decreasing -command 命令。返回一个新的列表。

concat arg arg arg ...

将多个列表连接起来,成为一个列表。

join list joinString

通过用 joinString 分隔列表中的元素,从而将它们合并起来。

split string splitChars

将字符串完全分割为列表元素,使用 splitChars 中的字符作为列表元素间的边界。

数组

数组是 Jacl 语言中的另一主要数据结构。数组是具有已赋值的字符串索引的变量,因此您可以将数组看作是从字符串到字符串的映射。数组在内部用散列表实现。访问每个元素 的成本几乎相同。数组的索引由圆括号定界。索引可以有任何字符串值,而且它可以是变量或命令替换的结果。数组元素用 set 命令定义,例如:

set arr(index) value

替换美元标记( $)以包含数组元素的值,例如:

set foo $arr(index)

例如:

set fruit(best) kiwi
=> kiwi
 
set fruit(worst) peach
=> peach
 
set fruit(ok) banana
=> banana
 
array get fruit
=> ok banana worst peach best kiwi
 
array exists fruit
=> 1

下表包含数组命令:

命令

描述

array exists arr

如果 arr 是数组变量,那么返回 1

array get arr

返回以索引和相应的数组值交替出现的列表。

array names arr ?pattern?

返回为 arr 定义的所有索引或匹配字符串匹配模式的索引列表。

array set arr list

初始化列表的数组 arr,该列表应该与 get 返回的列表具有相同格式。

array size arr

返回为 arr 定义的索引数。

array startsearch arr

返回搜索整个 arr 的搜索令牌。

array nextelement arr id

在由令牌标识识别的搜索中,返回数组中下一个元素的值。如果搜索中不再有元素,那么返回空字符串。

array anymore arr id

如果搜索中还有元素,那么返回 1

array donesearch arr id

结束由 id 识别的搜索。

控制流命令

存在以下循环命令:

  • while
  • foreach
  • for

以下是条件命令:

  • if
  • switch

以下是错误处理命令:

  • catch

以下命令微调控制流:

  • break
  • continue
  • return
  • error

If Then Else

if 命令是基本条件命令。它说明:如果表达式为真,那么返回第二个代码行,否则运行另一代码行。第二个命令主体( else 子句)是可选的。命令语法如下:

if  



boolean  



then  



body1  



else  



body2

then else 关键字是可选的。例如:

if {$x == 0} {
 puts stderr "Divide by zero!"
} else {
 set slope [expr $y/$x]
}

Switch

根据表达式的值,使用 switch 命令分支到多条命令中的某条命令。您可以基于模式匹配和简单比较来进行选择。可以指定任何数量的模式 -主体对。如果多个模式匹配,那么只对第一个匹配模式的代码主体求值。该命令的一般格式如下:

switch  



flags  



value  



pat1  



body1  



pat2  



body2  



...

您还可以将所有模式 -主体对分组到一个参数中:

switch  



flags  



value  



{pat1  



body1  



pat2  



body2  



...}

有四个可能的标志确定值如何匹配。

  • -exact 将值与某个模式完全匹配。
  • -glob 使用通配符样式模式匹配。
  • -regexp 使用正则表达式模式匹配。
  • -- 没有标志(或标志结束)。当值可以用虚线( - )开头时有用。

例如:

switch  



-exact  



--  



$value  



{
 foo  



{doFoo;  



incr  



count(foo)}
 bar    



{doBar;  



return  



$count(foo)}
 default   



{incr  



count(other)}
}

如果与上一个主体关联的模式是 default ,那么没有其他模式匹配时启动该命令主体。 default 关键字仅对上一个模式 /主体对起作用。如果对更前面的主体使用缺省模式,那么会将它作为模式对待以匹配文字串缺省值。

Foreach

foreach 命令循环整个命令主体,并将循环变量指定给列表中的每个值。语法如下:

foreach loopVar valueList commandBody

第一个参数是变量名。命令主体对循环中的每个元素运行一次,且循环变量有列表中的连续值。例如:

set numbers {1 3 5 7 11 13}
foreach num $numbers {
puts $num
}

假定环境中只存在一台服务器,上一个示例的结果将为以下输出。如果存在多台服务器,那么返回所有服务器的信息:

13 5711
13

While

while 命令采用两个参数;测试和命令主体,例如:

while  



booleanExpr  



body

如果表达式为 true(非零),那么 while 命令重复测试布尔表达式并运行主体。例如:

set i 0
while {$i < 5} {
puts "i is $i"
incr i} 

假定只有一台服务器,上一个示例的结果将类似以下输出。如果存在多台服务器,那么将打印所有服务器:

i is 0
i is 1
i is 2
i is 3
i is 4

For

for 命令类似于 C 语言的 for 语句。它采用四个参数,例如:

for initial test final body

第一个参数是初始化循环的命令。第二个参数是确定循环主体是否将运行的布尔表达式。第三个参数是在循环主体后运行的命令,例如:

set numbers {1 3 5 7 11 13}
for {set i 0} {$i < [llength $numbers]} {incr i 1} {
puts "i is $i"
} 

假定环境中只有一台服务器,上一个示例的结果将类似以下输出。如果存在多台服务器,那么它将打印所有服务器名:

i is 1
i is 3
i is 5
i is 7
i is 11
i is 13

break continue

您可以使用 break continue 命令控制循环执行。 break 命令会导致立即从循环中退出。 continue 命令会导致循环继续执行下一个迭代。

Catch

如果用错误的参数数调用命令,或者如果命令检测到特定于其实现的某些出错条件,将产生错误。未获取的错误会阻止脚本运行。使用 catch 命令获取这种错误。 catch 命令采用两个参数,例如:

catch command ?resultVar? 

第一个参数是命令主体。第二个参数是变量名,它将包含命令结果或错误消息(如果命令产生错误)。如果没有获取错误,那么 catch 命令返回值 0,如果该命令获取了错误,那么返回值 1。例如:

catch {expr 20 / 5} result
==> 0
puts $result
==> 4
catch {expr text / 5} result
==> 1
puts $result
==> syntax error in expression "text / 5"

Return

在过程主体结束前之前或在需要返回对比值时,请使用 return 命令来返回值。

Namespaces

Jacl 将一些命名实体(例如,变量)保存在名称空间中。 wsadmin 工具还将条目添加到脚本编制对象(例如, AdminApp 对象)的全局名称空间。

运行 proc 命令时,用 proc 命令中的参数名称和参数值创建和初始化了本地名称空间。运行 proc 命令时,变量保存在本地名称空间中。停止 proc 命令时,将擦除本地名称空间。 proc 命令的本地名称空间实现语言(例如, C Java)中自动变量的语义。

当全局名称空间中的变量对于顶层代码可视时,缺省情况下它们从 proc 命令内不可视。要使它们可视,请使用 global 命令全局声明这些变量。对于您提供的变量名,全局命令在本地名称空间中创建条目,它们指向实际定义这些变量的全局名称空间条目。

如果在 proc 中使用 wsadmin 工具提供的脚本编制对象,那么必须在可以使用它前先全局声明,例如:

proc { ... } {
               



global AdminConfig
               



... [$AdminConfig ...]
}

使用一个脚本调用其他脚本

请使用 source 命令来从一个 Jacl 脚本调用另一个 Jacl 脚本。例如:

创建称为 test1.jacl 的脚本。

source c:/temp/script/testProcedure.jacl
printName Cathy Smith

创建称为 testProcedure.jacl 的脚本。

proc printName {first last} {
        



puts "My name is $first $last"
}

请将以下路径作为脚本参数进行传递。

wsadmin -lang jacl -f c:/temp/script/test1.jacl

必须将正斜杠( /)用作路径分隔符。反斜杠( \)将不起作用。

使用 exec 命令重定向

以下用于重定向的 Jacl exec 命令在 Linux 平台上不起作用:

eval exec ls -l > /tmp/out

Jacl 脚本编制语言的 exec 命令不完全支持重定向,因此该命令在某些平台上可能会产生问题。

使用 Jacl 语言的 exec 命令时,不要使用重定向。相反,可以将用于重定向的 exec 命令保存在一个变量中,然后将该变量写入文件,例如:

open /tmp/out w puts $fileId $result close $fileId

在某些情况下,还可以使用 shell .sh 命令重定向(而不是 Tcl 发出的重定向)来执行重定向。

要获取更多有关 Jacl 的信息,请参阅 脚本编制:学习资源 一文。

 

<!---->

分享到:
评论

相关推荐

    com.springsource.tcl.lang.jacl-1.4.1生成报错替换包.zip

    Jacl(Java Command Language)是TCL的一个实现,它允许TCL脚本在Java平台上运行,提供了与Java的紧密集成。SpringSource是一家知名的Java技术提供商,他们为许多开源项目提供了支持,包括这个TCL的Java接口。 "jar...

    JACL A TCL implementation in Java.pdf

    ### Jacl:一种基于Java环境的Tcl实现 #### 概述 《Jacl:一种Tcl在Java环境中的实现》是一篇详细介绍了如何将Tcl脚本语言与Java技术结合的文章。该文最初发表于1997年波士顿第五届年度Tcl/Tk研讨会的论文集中。...

    tcl.lang.Interp 依赖包jacl-1.2.6.jar

    tcl.lang.Interp 依赖包jacl-1.2.6.jar

    基于RationalSoftwareArchitect实现SIBus模型到Jacl脚本的转换

    火龙果软件工程技术中心本文内容包括:1RSA的模型转换框架2WebSphere与Jacl语言3服务集成总线建模(SIBUS)4SIBUS模型到Jacl脚本的转换开发结束语参考资料RationalSoftwareArchitect(RSA)是IBMRational软件家族中的...

    Tcl_Java.zip

    在压缩包中的文件 "JACL+A+TCL+implementation+in+Java.pdf" 很可能是关于JACL的详细教程或技术文档,涵盖了JACL的安装、配置、使用方法以及实际案例。而 "jaclBinary141.zip" 文件可能包含了JACL的二进制版本,供...

    北京顺义测试题以及报错总结.zip

    2. **错误类型和原因**:针对每一道题目或者报错实例,文档会解释出错的原因,可能是语法错误、逻辑错误,或者是配置问题、兼容性问题等。 3. **错误解决步骤**:在分析完错误原因后,会给出详细的解决步骤,包括...

    中文Lotus_Domino_R5_Web_高级编程

    Lotus Domino R5是一款在20世纪末到21世纪初广泛应用的企业级协同软件平台,它集成了电子邮件、日程管理、文档共享、数据库和Web应用开发等功能。此资源"中文Lotus_Domino_R5_Web_高级编程.rar"似乎包含了一份关于...

    wsadmin auto deploy

    it is a sample for websphere application server's asset wsadmin. use wsadmin & jacl you can auto deploy your enterprise archive file.

    Domino编程

    4. **Java API for Lotus Domino (JACL)**:对于更复杂的应用需求,开发者可以使用JACL进行服务器端编程,JACL提供了与LotusScript类似的接口,但使用Java语言,可以充分利用Java的强大功能。 5. **XPages**:随着...

    EvolvingTheJavaPlatform-OlaBini.pdf

    本资源摘要信息的标题是"Evolving the Java Platform-Ola Bini.pdf",该文件是一份技术文档分享,标签为"技术文档分享"。在这份文件中,作者 Ola Bini 介绍了 Java 平台的演进,讨论了其他语言对 Java 平台的影响,...

    tcl:Tcl核心。 (core.tcl-lang.org的镜像)

    自述文件:Tcl 这是Tcl 9.0a2源分发。 您可以从获得Tcl的任何源版本。 8.6(生产发布,每日构建) 8.7(开发中,每日构建) 9.0(开发中,每日构建)内容简介Tcl提供了一个强大的平台来创建将各种应用程序,协议,...

    Java 对 Domino 的访问

    1. **Java API for Lotus Domino (JACL)**:这是IBM提供的一套Java接口,使得开发者可以使用Java来操作Domino对象,如数据库、文档、视图、表单等。 2. ** Domino JNA (Java Native Access)**:这是一种技术,通过...

    websphere 脚本配置

    - 运行Jacl脚本:`wsadmin.bat -profile sample.jacl` - 运行Jython脚本:`wsadmin.bat -lang jython -profile sample.py` ### Jython语言介绍 Jython是动态类型的,不需要提前声明变量类型。其基本数据类型包括...

    Tcl/CSharp-开源

    Tcl / CSharp是完全用C#编写的Tcl解释器的实现。 Tcl / CSharp是从Jacl(Tcl Java实现)版本1.3.1移植而来的,它为Tcl代码提供了到.NET Framework的桥梁。

    JFCML - JFC/Swing XML Markup Language-开源

    唯一的,完整的Java XUL /嵌入式脚本解决方案。 JFCML不仅仅支持AWT和Swing;还支持AWT和Swing。 但是Java的ClassLoader... 此外,大多数主要的脚本语言,包括JavaScript,BeanShell,Jython,Jacl(Tcl),JRuby等。

    IBMWebspherePortal管理工具-----XML配置接口参照.pdf

    - **Portal脚本**:基于Websphere扩展,支持TCL和JACL脚本,适用于复杂的管理任务,例如用户迁移和数据库迁移。它还整合了ANT的构建和批处理功能。 - **XML配置接口**:通过XML文件直接修改Portal配置,支持导入...

    was与 web 服务器通信.doc

    - 或者,使用ConfigureWebServerDefinition.jacl脚本来自动化此过程。 5. **应用程序映射** - 应用程序在安装时会被自动映射到Web服务器,或者在安装后手动进行映射。 6. **配置插件** - 可以通过管理控制台或...

Global site tag (gtag.js) - Google Analytics